diff --git a/.coderabbit.yaml b/.coderabbit.yaml index 46e2d25b8c..08e1985ae7 100644 --- a/.coderabbit.yaml +++ b/.coderabbit.yaml @@ -13,5 +13,6 @@ reviews: drafts: false base_branches: - develop + - main chat: - auto_reply: true \ No newline at end of file + auto_reply: true diff --git a/.eslintrc.json b/.eslintrc.json index ee118a5a58..26470f7aab 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -60,7 +60,9 @@ "@typescript-eslint/no-non-null-asserted-optional-chain": "error", "@typescript-eslint/no-non-null-assertion": "error", "@typescript-eslint/no-var-requires": "error", - "@typescript-eslint/ban-types": "error", + "@typescript-eslint/no-unsafe-function-type": "error", + "@typescript-eslint/no-wrapper-object-types": "error", + "@typescript-eslint/no-empty-object-type": "error", "@typescript-eslint/no-duplicate-enum-values": "error", "@typescript-eslint/array-type": "error", "@typescript-eslint/consistent-type-assertions": "error", diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index 493322305f..d9f95c0d65 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -31,4 +31,6 @@ If applicable, add screenshots to help explain your problem. Add any other context or screenshots about the feature request here. **Potential internship candidates** -Please read this if you are planning to apply for a Palisadoes Foundation internship https://github.com/PalisadoesFoundation/talawa/issues/359 + +Please read this if you are planning to apply for a Palisadoes Foundation internship +- https://github.com/PalisadoesFoundation/talawa/issues/359 diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md index 60d6401dcf..51aea0e9d9 100644 --- a/.github/ISSUE_TEMPLATE/feature-request.md +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -23,4 +23,6 @@ A clear and concise description of approach to be followed. Add any other context or screenshots about the feature request here. **Potential internship candidates** -Please read this if you are planning to apply for a Palisadoes Foundation internship https://github.com/PalisadoesFoundation/talawa/issues/359 + +Please read this if you are planning to apply for a Palisadoes Foundation internship +- https://github.com/PalisadoesFoundation/talawa/issues/359 diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml index 2fc49726ff..9a3e9a54e9 100644 --- a/.github/dependabot.yaml +++ b/.github/dependabot.yaml @@ -7,7 +7,7 @@ updates: directory: "/" # Schedule automated updates to run weekly schedule: - interval: "weekly" + interval: "monthly" # Labels to apply to Dependabot PRs labels: - "dependencies" @@ -15,4 +15,4 @@ updates: target-branch: "develop" # Customize commit message prefix commit-message: - prefix: "chore(deps):" \ No newline at end of file + prefix: "chore(deps):" diff --git a/.github/workflows/check-tsdoc.js b/.github/workflows/check-tsdoc.js new file mode 100644 index 0000000000..d5c3b33b90 --- /dev/null +++ b/.github/workflows/check-tsdoc.js @@ -0,0 +1,68 @@ +import fs from 'fs/promises'; // Import fs.promises for async operations +import path from 'path'; + +// List of files to skip +const filesToSkip = [ + 'index.tsx', + 'EventActionItems.tsx', + 'OrgPostCard.tsx', + 'UsersTableItem.tsx', + 'FundCampaignPledge.tsx' +]; + +// Recursively find all .tsx files, excluding files listed in filesToSkip +async function findTsxFiles(dir) { + let results = []; + try { + const list = await fs.readdir(dir); + for (const file of list) { + const filePath = path.join(dir, file); + const stat = await fs.stat(filePath); + if (stat.isDirectory()) { + results = results.concat(await findTsxFiles(filePath)); + } else if ( + filePath.endsWith('.tsx') && + !filePath.endsWith('.test.tsx') && + !filesToSkip.includes(path.relative(dir, filePath)) + ) { + results.push(filePath); + } + } + } catch (err) { + console.error(`Error reading directory ${dir}: ${err.message}`); + } + return results; +} + +// Check if a file contains at least one TSDoc comment +async function containsTsDocComment(filePath) { + try { + const content = await fs.readFile(filePath, 'utf8'); + return /\/\*\*[\s\S]*?\*\//.test(content); + } catch (err) { + console.error(`Error reading file ${filePath}: ${err.message}`); + return false; + } +} + +// Main function to run the validation +async function run() { + const dir = process.argv[2] || './src'; // Allow directory path as a command-line argument + const files = await findTsxFiles(dir); + const filesWithoutTsDoc = []; + + for (const file of files) { + if (!await containsTsDocComment(file)) { + filesWithoutTsDoc.push(file); + } + } + + if (filesWithoutTsDoc.length > 0) { + filesWithoutTsDoc.forEach(file => { + console.error(`No TSDoc comment found in file: ${file}`); + }); + process.exit(1); + } +} + +run(); \ No newline at end of file diff --git a/.github/workflows/codeql-codescan.yml b/.github/workflows/codeql-codescan.yml index e9eb5c5d49..6fa463001f 100644 --- a/.github/workflows/codeql-codescan.yml +++ b/.github/workflows/codeql-codescan.yml @@ -20,7 +20,8 @@ on: - '**' jobs: CodeQL: - name: Analyse code with codeQL on push + if: ${{ github.actor != 'dependabot[bot]' }} + name: Analyse Code With CodeQL runs-on: ubuntu-latest strategy: fail-fast: false diff --git a/.github/workflows/compare_translations.py b/.github/workflows/compare_translations.py index fd4f772605..ef65b6c52b 100644 --- a/.github/workflows/compare_translations.py +++ b/.github/workflows/compare_translations.py @@ -88,6 +88,31 @@ def compare_translations(default_translation, errors.append(error_msg) return errors +def flatten_json(nested_json, parent_key=""): + """ + Flattens a nested JSON, concatenating keys to represent the hierarchy. + + Args: + nested_json (dict): The JSON object to flatten. + parent_key (str): The base key for recursion (used to track key hierarchy). + + Returns: + dict: A flattened dictionary with concatenated keys. + """ + flat_dict = {} + + for key, value in nested_json.items(): + # Create the new key by concatenating parent and current key + new_key = f"{parent_key}.{key}" if parent_key else key + + if isinstance(value, dict): + # Recursively flatten the nested dictionary + flat_dict.update(flatten_json(value, new_key)) + else: + # Assign the value to the flattened key + flat_dict[new_key] = value + + return flat_dict def load_translation(filepath): """Load translation from a file. @@ -104,7 +129,8 @@ def load_translation(filepath): if not content.strip(): raise ValueError(f"File {filepath} is empty.") translation = json.loads(content) - return translation + flattened_translation = flatten_json(translation) + return flattened_translation except json.JSONDecodeError as e: raise ValueError(f"Error decoding JSON from file {filepath}: {e}") @@ -170,7 +196,7 @@ def main(): "--directory", type=str, nargs="?", - default=os.path.join(os.getcwd(), "locales"), + default=os.path.join(os.getcwd(), "public/locales"), help="Directory containing translation files(relative to the root directory).", ) args = parser.parse_args() diff --git a/.github/workflows/eslint_disable_check.py b/.github/workflows/eslint_disable_check.py index 1efa49feb4..201b4462b8 100644 --- a/.github/workflows/eslint_disable_check.py +++ b/.github/workflows/eslint_disable_check.py @@ -36,9 +36,15 @@ def has_eslint_disable(file_path): Returns: bool: True if eslint-disable statement is found, False otherwise. """ - with open(file_path, 'r') as file: - content = file.read() - return re.search(r'//\s*eslint-disable', content) + eslint_disable_pattern = re.compile(r'//\s*eslint-disable(?:-next-line|-line)?', re.IGNORECASE) + + try: + with open(file_path, 'r', encoding='utf-8') as file: + content = file.read() + return bool(eslint_disable_pattern.search(content)) + except Exception as e: + print(f"Error reading file {file_path}: {e}") + return False def check_eslint(directory): """ @@ -72,7 +78,6 @@ def arg_parser_resolver(): Returns: result: Parsed argument object - """ parser = argparse.ArgumentParser() parser.add_argument( @@ -98,7 +103,6 @@ def main(): Raises: SystemExit: If an error occurs during execution. """ - args = arg_parser_resolver() if not os.path.exists(args.directory): diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 1ec7380c6c..ac079715a1 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -30,7 +30,7 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v4 with: - node-version: '20.x' + node-version: '22.x' - name: Install Dependencies run: npm install @@ -38,7 +38,7 @@ jobs: - name: Count number of lines run: | chmod +x ./.github/workflows/countline.py - ./.github/workflows/countline.py --lines 600 --exclude_files src/screens/LoginPage/LoginPage.tsx src/GraphQl/Queries/Queries.ts src/screens/OrgList/OrgList.tsx src/GraphQl/Mutations/mutations.ts src/components/EventListCard/EventListCardModals.tsx + ./.github/workflows/countline.py --lines 600 --exclude_files src/screens/LoginPage/LoginPage.tsx src/GraphQl/Queries/Queries.ts src/screens/OrgList/OrgList.tsx src/GraphQl/Mutations/mutations.ts src/components/EventListCard/EventListCardModals.tsx src/screens/ManageTag/ManageTag.tsx - name: Get changed TypeScript files id: changed-files @@ -56,8 +56,11 @@ jobs: if: steps.changed-files.outputs.only_changed != 'true' env: CHANGED_FILES: ${{ steps.changed_files.outputs.all_changed_files }} - run: npx eslint ${CHANGED_FILES} + run: npx eslint ${CHANGED_FILES} && python .github/workflows/eslint_disable_check.py + - name: Check for TSDoc comments + run: npm run check-tsdoc # Run the TSDoc check script + - name: Check for localStorage Usage run: | chmod +x scripts/githooks/check-localstorage-usage.js @@ -76,8 +79,9 @@ jobs: echo "Error: Source and Target Branches are the same. Please ensure they are different." exit 1 - Check-Unauthorized-Changes: - name: Checks if no unauthorized files are changed + Check-Sensitive-Files: + if: ${{ github.actor != 'dependabot[bot]' }} + name: Checks if sensitive files have been changed without authorization runs-on: ubuntu-latest steps: - name: Checkout code @@ -107,6 +111,14 @@ jobs: LICENSE setup.ts .coderabbit.yaml + CODE_OF_CONDUCT.md + CODE_STYLE.md + CONTRIBUTING.md + DOCUMENTATION.md + INSTALLATION.md + ISSUE_GUIDELINES.md + PR_GUIDELINES.md + README.md - name: List all changed unauthorized files if: steps.changed-unauth-files.outputs.any_changed == 'true' || steps.changed-unauth-files.outputs.any_deleted == 'true' @@ -119,6 +131,7 @@ jobs: exit 1 Count-Changed-Files: + if: ${{ github.actor != 'dependabot[bot]' }} name: Checks if number of files changed is acceptable runs-on: ubuntu-latest steps: @@ -173,7 +186,7 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v4 with: - node-version: '20.x' + node-version: '22.x' - name: Install Dependencies run: npm install @@ -209,6 +222,7 @@ jobs: min_coverage: 95.0 Graphql-Inspector: + if: ${{ github.actor != 'dependabot[bot]' }} name: Runs Introspection on the GitHub talawa-api repo on the schema.graphql file runs-on: ubuntu-latest steps: @@ -218,7 +232,7 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v4 with: - node-version: '20.x' + node-version: '22.x' - name: resolve dependency run: npm install -g @graphql-inspector/cli @@ -236,6 +250,7 @@ jobs: run: graphql-inspector validate './src/GraphQl/**/*.ts' './talawa-api/schema.graphql' Check-Target-Branch: + if: ${{ github.actor != 'dependabot[bot]' }} name: Check Target Branch runs-on: ubuntu-latest steps: diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 0542490787..950d063fac 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -21,10 +21,12 @@ env: jobs: Code-Coverage: + if: ${{ github.actor != 'dependabot[bot]' }} + name: Test and Calculate Code Coverage runs-on: ubuntu-latest strategy: matrix: - node-version: [20.x] + node-version: [22.x] steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -58,128 +60,3 @@ jobs: fail_ci_if_error: false name: '${{env.CODECOV_UNIQUE_NAME}}' - Generate-Documentation: - runs-on: ubuntu-latest - if: github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/automated-docs' - steps: - - name: Checkout the Repository - uses: actions/checkout@v4 - # with: - # ref: develop - - # - name: Pull latest changes from develop - # run: git pull origin develop - - - name: Node.js Version - uses: actions/setup-node@v4 - with: - node-version: '20' - - - name: Restore node_modules from cache - id: cache-npm - uses: actions/cache@v4 - env: - cache-name: cache-node-modules - with: - path: | - ~/.npm - node_modules - key: ${{ runner.os }}-generate-docs-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-generate-docs-${{ env.cache-name }}- - ${{ runner.os }}-generate-docs- - ${{ runner.os }}- - - - name: Install dependencies - run: npm install - - - name: Install TypeScript Globally and add GraphQL tag - run: yarn global add typescript - - run: yarn add graphql-tag - - - name: Update Dependencies - run: yarn upgrade - - - name: Generate Documentation of Markdown pages - run: | - npm install --global typedoc - npm install typedoc-plugin-markdown - npm install --save-dev @types/node - npx typedoc --entryPoints src/components src/screens --out talawa-admin-docs --plugin typedoc-plugin-markdown --theme markdown --entryPointStrategy expand --exclude "**/*.test.ts" --exclude "**/*.css" - - - name: Make Markdown Files MDX Compatible - run: python ./.github/workflows/md_mdx_format_adjuster.py --directory talawa-admin-docs - - - - name: Checking doc updated - id: DocUpdated - run: | - if [ -n "$(git status --porcelain)" ]; then - echo "updateDoc=true" >> $GITHUB_OUTPUT - echo -e "Documentation has been updated!!" - else - Green='0;32' - NoColor='\033[0m' - echo -e "${Green}No documentation updated${NoColor}" - fi - - - name: Set env variables - if: steps.DocUpdated.outputs.updateDoc - run: | - echo "commit_id=$(echo $(git rev-parse HEAD))" >> $GITHUB_ENV - echo "email=$(echo $(git log --pretty=format:"%ae" $commit_id))" >> $GITHUB_ENV - - - name: Update Doc - if: steps.DocUpdated.outputs.updateDoc - run: | - Green='0;32' - NoColor='\033[0m' - git config --global user.name "${{github.actor}}" - git config --global user.email "${{env.email}}" - git add . - git commit -m "Update documentation" - git push origin develop:automated-docs --force - echo -e "🚀${Green} Hurrah! doc updated${NoColor}" - - - name: Create Documentation Artifact - uses: actions/upload-artifact@v2 - with: - name: documentation-admin - path: talawa-admin-docs - - Empty-Commit: - name: Create Empty Commit - runs-on: ubuntu-latest - if: github.ref == 'refs/heads/develop' - needs: Generate-Documentation - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - persist-credentials: false - token: ${{ secrets.TALAWA_DOCS_SYNC }} - - name: Empty Commit - run: | - git config --global user.name "${{github.actor}}" - git config --global user.email "${{env.email}}" - git config --global url.https://${{ secrets.TALAWA_DOCS_SYNC }}@github.com/.insteadOf https://github.com/ - git commit --allow-empty -m "Trigger Documentation Workflow" - git push origin develop:automated-docs --force - - Copy-docs-to-talawa-docs: - if: github.ref == 'refs/heads/automated-docs' - needs: Generate-Documentation - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: dmnemec/copy_file_to_another_repo_action@v1.1.1 - env: - API_TOKEN_GITHUB: ${{secrets.TALAWA_DOCS_SYNC}} - with: - source_file: 'talawa-admin-docs/' - destination_repo: 'PalisadoesFoundation/talawa-docs' - destination_branch: 'develop' - destination_folder: 'docs/' - user_email: '${{env.email}}' - user_name: '${{github.actor}}' - commit_message: 'Talawa Admin docs updated' diff --git a/.github/workflows/md_mdx_format_adjuster.py b/.github/workflows/talawa_admin_md_mdx_format_adjuster.py similarity index 99% rename from .github/workflows/md_mdx_format_adjuster.py rename to .github/workflows/talawa_admin_md_mdx_format_adjuster.py index c33ad1fa66..cd76a30cf6 100644 --- a/.github/workflows/md_mdx_format_adjuster.py +++ b/.github/workflows/talawa_admin_md_mdx_format_adjuster.py @@ -12,7 +12,6 @@ 3) Pycodestyle 4) Flake8 """ - import os import argparse import re diff --git a/.node-version b/.node-version index 790e1105f2..751f4c9f38 100644 --- a/.node-version +++ b/.node-version @@ -1 +1 @@ -v20.10.0 +v22.7.0 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 47fa8d6e69..dbe448c807 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,6 +9,7 @@ If you are new to contributing to open source, please read the Open Source Guide - [Code of Conduct](#code-of-conduct) +- [Videos](#videos) - [Ways to Contribute](#ways-to-contribute) - [Our Development Process](#our-development-process) - [Issues](#issues) @@ -27,6 +28,11 @@ A safe environment is required for everyone to contribute. Read our [Code of Con No one should fear voicing their opinion. Respones must be respectful. +## Videos + +1. Visit our [YouTube Channel playlists](https://www.youtube.com/@PalisadoesOrganization/playlists) for more insights + 1. The "[Getting Started - Developers](https://www.youtube.com/watch?v=YpBUoHxEeyg&list=PLv50qHwThlJUIzscg9a80a9-HmAlmUdCF&index=1)" videos are extremely helpful for new open source contributors. + ## Ways to Contribute If you are ready to start contributing code right away, get ready! diff --git a/README.md b/README.md index 21692075fc..cbade9e407 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ Core features include: 1. The `talawa` documentation can be found at our [docs.talawa.io](https://docs.talawa.io) site. 1. It is automatically generated from the markdown files stored in our [Talawa-Docs GitHub repository](https://github.com/PalisadoesFoundation/talawa-docs). This makes it easy for you to update our documenation. -# Videos +# Videos 1. Visit our [YouTube Channel playlists](https://www.youtube.com/@PalisadoesOrganization/playlists) for more insights - 1. The "Getting Started - Developers" videos are extremely helpful for new open source contributors. + 1. The "[Getting Started - Developers](https://www.youtube.com/watch?v=YpBUoHxEeyg&list=PLv50qHwThlJUIzscg9a80a9-HmAlmUdCF&index=1)" videos are extremely helpful for new open source contributors. diff --git a/config/babel.config.cjs b/config/babel.config.cjs new file mode 100644 index 0000000000..10cfe1914a --- /dev/null +++ b/config/babel.config.cjs @@ -0,0 +1,8 @@ +module.exports = { + presets: [ + '@babel/preset-env', // Transforms modern JavaScript + '@babel/preset-typescript', // Transforms TypeScript + '@babel/preset-react', // Transforms JSX + ], + plugins: ['babel-plugin-transform-import-meta'], +}; diff --git a/config/vite.config.ts b/config/vite.config.ts new file mode 100644 index 0000000000..71ce6c6f47 --- /dev/null +++ b/config/vite.config.ts @@ -0,0 +1,30 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; +import viteTsconfigPaths from 'vite-tsconfig-paths'; +import svgrPlugin from 'vite-plugin-svgr'; +import EnvironmentPlugin from 'vite-plugin-environment'; + +export default defineConfig({ + // depending on your application, base can also be "/" + build: { + outDir: 'build', + }, + base: '', + plugins: [ + react(), + viteTsconfigPaths(), + EnvironmentPlugin('all'), + svgrPlugin({ + svgrOptions: { + icon: true, + // ...svgr options (https://react-svgr.com/docs/options/) + }, + }), + ], + server: { + // this ensures that the browser opens upon server start + open: true, + // this sets a default port to 3000 + port: 4321, + }, +}); diff --git a/public/index.html b/index.html similarity index 64% rename from public/index.html rename to index.html index 3bd6e258e7..4375f88592 100644 --- a/public/index.html +++ b/index.html @@ -1,12 +1,12 @@ - + - + - - + + - + Talawa Admin
+ diff --git a/jest.config.js b/jest.config.js index 34f219ba06..4346984c74 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,7 +1,8 @@ export default { roots: ['/src'], collectCoverageFrom: ['src/**/*.{ts,tsx}', '!src/index.tsx'], - setupFiles: ['react-app-polyfill/jsdom'], + // setupFiles: ['react-app-polyfill/jsdom'], + setupFiles: ['whatwg-fetch'], setupFilesAfterEnv: ['/src/setupTests.ts'], testMatch: [ '/src/**/__tests__/**/*.{js,jsx,ts,tsx}', @@ -9,11 +10,9 @@ export default { ], testEnvironment: 'jsdom', transform: { - '^.+\\.(js|jsx|mjs|cjs|ts|tsx)$': - 'react-scripts/config/jest/babelTransform.js', - '^.+\\.(css|scss|sass|less)$': 'jest-preview/transforms/css', - '^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)': - 'jest-preview/transforms/file', + '^.+\\.(js|jsx|ts|tsx)$': ['babel-jest', { configFile: "./config/babel.config.cjs" }], // Use babel-jest for JavaScript and TypeScript files + '^.+\\.(css|scss|sass|less)$': 'jest-preview/transforms/css', // CSS transformations + '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': 'jest-preview/transforms/file', // File transformations }, transformIgnorePatterns: [ '[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs|cjs|ts|tsx)$', @@ -28,6 +27,8 @@ export default { '^@dicebear/core$': '/scripts/__mocks__/@dicebear/core.ts', '^@dicebear/collection$': '/scripts/__mocks__/@dicebear/collection.ts', + '\\.svg\\?react$': '/scripts/__mocks__/fileMock.js', + '\\.svg$': '/scripts/__mocks__/fileMock.js', }, moduleFileExtensions: [ 'web.js', @@ -41,10 +42,10 @@ export default { 'jsx', 'node', ], - watchPlugins: [ - 'jest-watch-typeahead/filename', - 'jest-watch-typeahead/testname', - ], + // watchPlugins: [ + // 'jest-watch-typeahead/filename', + // 'jest-watch-typeahead/testname', + // ], resetMocks: false, coveragePathIgnorePatterns: [ 'src/state/index.ts', diff --git a/package-lock.json b/package-lock.json index ae4b723c47..934c2ecb52 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,95 +8,109 @@ "name": "talawa-admin", "version": "3.0.0", "dependencies": { - "@apollo/client": "^3.4.0-beta.19", + "@apollo/client": "^3.11.4", "@apollo/link-error": "^2.0.0-beta.3", "@apollo/react-testing": "^4.0.0", - "@dicebear/collection": "^8.0.1", - "@dicebear/core": "^8.0.1", - "@emotion/react": "^11.11.4", - "@emotion/styled": "^11.11.5", - "@mui/icons-material": "^5.8.3", - "@mui/material": "^5.15.20", + "@dicebear/collection": "^8.0.2", + "@dicebear/core": "^8.0.2", + "@emotion/react": "^11.13.3", + "@emotion/styled": "^11.13.0", + "@mui/icons-material": "^5.16.7", + "@mui/material": "^5.16.7", "@mui/private-theming": "^5.15.12", "@mui/system": "^5.14.12", - "@mui/x-charts": "^7.6.2", - "@mui/x-data-grid": "^6.20.0", - "@mui/x-date-pickers": "^7.6.1", - "@pdfme/generator": "^1.2.6", - "bootstrap": "^5.3.0", "chart.js": "^4.4.3", + "@mui/x-charts": "^7.17.0", + "@mui/x-data-grid": "^7.22.0", + "@mui/x-date-pickers": "^7.11.1", + "@pdfme/generator": "^4.5.2", + "@reduxjs/toolkit": "^2.3.0", + "@vitejs/plugin-react": "^4.3.2", + "babel-plugin-transform-import-meta": "^2.2.1", + "bootstrap": "^5.3.3", "customize-cra": "^1.0.0", - "dayjs": "^1.11.11", - "flag-icons": "^6.6.6", - "graphql": "^16.8.2", + "dayjs": "^1.11.13", + "dotenv": "^16.4.5", + "flag-icons": "^7.2.3", + "graphql": "^16.9.0", "graphql-tag": "^2.12.6", "graphql-ws": "^5.16.0", "history": "^5.3.0", - "html2canvas": "^1.4.1", "i18next": "^21.8.14", "i18next-browser-languagedetector": "^8.0.0", - "i18next-http-backend": "^1.4.1", + "i18next-http-backend": "^2.6.1", "inquirer": "^8.0.0", "js-cookie": "^3.0.1", "markdown-toc": "^1.2.0", - "prettier": "^3.2.5", - "react": "^17.0.2", - "react-app-rewired": "^2.2.1", - "react-bootstrap": "^2.7.4", - "react-chartjs-2": "^5.2.0", - "react-datepicker": "^4.2.0", - "react-dom": "^17.0.2", - "react-google-recaptcha": "^2.1.0", - "react-i18next": "^11.18.1", + "prettier": "^3.3.3", + "react": "^18.3.1", + "react-beautiful-dnd": "^13.1.1", + "react-bootstrap": "^2.10.5", + "react-datepicker": "^7.5.0", + "react-dom": "^18.3.1", + "react-google-recaptcha": "^3.1.0", + "react-i18next": "^15.0.2", "react-icons": "^5.2.1", "react-infinite-scroll-component": "^6.1.0", - "react-redux": "^7.2.5", - "react-router-dom": "^6.23.1", - "react-scripts": "5.0.1", - "react-toastify": "^9.0.3", - "redux": "^4.1.1", - "redux-thunk": "^2.3.0", + "react-multi-carousel": "^2.8.5", + "react-redux": "^9.1.2", + "react-router-dom": "^6.27.0", + "react-toastify": "^10.0.6", + "react-tooltip": "^5.28.0", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", "sanitize-html": "^2.13.0", - "typedoc-plugin-markdown": "^4.0.3", - "typescript": "^4.3.5", - "web-vitals": "^1.0.1" + "typedoc": "^0.26.10", + "typedoc-plugin-markdown": "^4.2.1", + "typescript": "^5.6.3", + "vite": "^5.4.8", + "vite-plugin-environment": "^1.1.3", + "vite-tsconfig-paths": "^5.0.1", + "web-vitals": "^4.2.4" }, "devDependencies": { "@babel/plugin-proposal-private-property-in-object": "^7.21.11", - "@testing-library/jest-dom": "^5.14.1", - "@testing-library/react": "^11.1.0", + "@babel/preset-env": "^7.25.4", + "@babel/preset-react": "^7.25.7", + "@babel/preset-typescript": "^7.24.7", + "@testing-library/jest-dom": "^6.5.0", + "@testing-library/react": "^16.0.1", "@testing-library/user-event": "^12.1.10", "@types/inquirer": "^9.0.7", "@types/jest": "^26.0.24", "@types/js-cookie": "^3.0.6", - "@types/node": "^20.12.12", + "@types/node": "^22.5.4", "@types/node-fetch": "^2.6.10", - "@types/react": "^17.0.14", + "@types/react": "^18.3.3", + "@types/react-beautiful-dnd": "^13.1.8", "@types/react-bootstrap": "^0.32.32", - "@types/react-datepicker": "^4.1.4", - "@types/react-dom": "^17.0.9", - "@types/react-google-recaptcha": "^2.1.5", + "@types/react-datepicker": "^7.0.0", + "@types/react-dom": "^18.3.0", + "@types/react-google-recaptcha": "^2.1.9", "@types/react-router-dom": "^5.1.8", - "@types/sanitize-html": "^2.11.0", - "@typescript-eslint/eslint-plugin": "^5.9.0", - "@typescript-eslint/parser": "^5.9.0", + "@types/sanitize-html": "^2.13.0", + "@typescript-eslint/eslint-plugin": "^8.11.0", + "@typescript-eslint/parser": "^8.5.0", + "babel-jest": "^29.7.0", "cross-env": "^7.0.3", "eslint-config-prettier": "^9.1.0", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jest": "^25.3.4", - "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-react": "^7.34.1", - "eslint-plugin-tsdoc": "^0.2.17", - "husky": "^8.0.3", + "eslint-plugin-import": "^2.30.0", + "eslint-plugin-jest": "^28.8.0", + "eslint-plugin-prettier": "^5.2.1", + "eslint-plugin-react": "^7.37.1", + "eslint-plugin-tsdoc": "^0.3.0", + "husky": "^9.1.6", "identity-obj-proxy": "^3.0.0", "jest": "^27.4.5", "jest-localstorage-mock": "^2.4.19", "jest-location-mock": "^2.0.0", "jest-preview": "^0.3.1", - "lint-staged": "^15.2.7", + "lint-staged": "^15.2.8", "postcss-modules": "^6.0.0", - "sass": "^1.77.4", - "tsx": "^4.15.5" + "sass": "^1.77.8", + "tsx": "^4.19.1", + "vite-plugin-svgr": "^4.2.0", + "whatwg-fetch": "^3.6.20" }, "engines": { "node": ">=20.x" @@ -106,26 +120,18 @@ "version": "1.2.6", "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "peer": true, "engines": { "node": ">=0.10.0" } }, "node_modules/@adobe/css-tools": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.3.tgz", - "integrity": "sha512-rE0Pygv0sEZ4vBWHlAgJLGDU7Pm8xoO6p3wsEceb7GYAjScrOHpEo8KK/eVkAcnSM+slAEtXjA2JpdjLp4fJQQ==", - "dev": true - }, - "node_modules/@alloc/quick-lru": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", - "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.0.tgz", + "integrity": "sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ==", + "dev": true, + "license": "MIT" }, "node_modules/@ampproject/remapping": { "version": "2.2.1", @@ -139,35 +145,20 @@ "node": ">=6.0.0" } }, - "node_modules/@apideck/better-ajv-errors": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@apideck/better-ajv-errors/-/better-ajv-errors-0.3.6.tgz", - "integrity": "sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA==", - "dependencies": { - "json-schema": "^0.4.0", - "jsonpointer": "^5.0.0", - "leven": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "ajv": ">=8" - } - }, "node_modules/@apollo/client": { - "version": "3.7.17", - "resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.7.17.tgz", - "integrity": "sha512-0EErSHEtKPNl5wgWikHJbKFAzJ/k11O0WO2QyqZSHpdxdAnw7UWHY4YiLbHCFG7lhrD+NTQ3Z/H9Jn4rcikoJA==", + "version": "3.11.4", + "resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.11.4.tgz", + "integrity": "sha512-bmgYKkULpym8wt8aXlAZ1heaYo0skLJ5ru0qJ+JCRoo03Pe+yIDbBCnqlDw6Mjj76hFkDw3HwFMgZC2Hxp30Mg==", "dependencies": { "@graphql-typed-document-node/core": "^3.1.1", - "@wry/context": "^0.7.0", - "@wry/equality": "^0.5.0", - "@wry/trie": "^0.4.0", + "@wry/caches": "^1.0.0", + "@wry/equality": "^0.5.6", + "@wry/trie": "^0.5.0", "graphql-tag": "^2.12.6", "hoist-non-react-statics": "^3.3.2", - "optimism": "^0.16.2", + "optimism": "^0.18.0", "prop-types": "^15.7.2", + "rehackt": "^0.1.0", "response-iterator": "^0.2.6", "symbol-observable": "^4.0.0", "ts-invariant": "^0.10.3", @@ -175,10 +166,10 @@ "zen-observable-ts": "^1.2.5" }, "peerDependencies": { - "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0", + "graphql": "^15.0.0 || ^16.0.0", "graphql-ws": "^5.5.5", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0", "subscriptions-transport-ws": "^0.9.0 || ^0.11.0" }, "peerDependenciesMeta": { @@ -219,108 +210,45 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", - "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.25.7.tgz", + "integrity": "sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g==", + "license": "MIT", "dependencies": { - "@babel/highlight": "^7.23.4", - "chalk": "^2.4.2" + "@babel/highlight": "^7.25.7", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/code-frame/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/code-frame/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/code-frame/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/code-frame/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/code-frame/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/@babel/code-frame/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/code-frame/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/compat-data": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", - "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.4.tgz", + "integrity": "sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.9.tgz", - "integrity": "sha512-G2EgeufBcYw27U4hhoIwFcgc1XU7TlXJ3mv04oOv1WCuo900U/anZSPzEqNjwdjgffkk2Gs0AN0dW1CKVLcG7w==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", + "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.22.5", - "@babel/generator": "^7.22.9", - "@babel/helper-compilation-targets": "^7.22.9", - "@babel/helper-module-transforms": "^7.22.9", - "@babel/helpers": "^7.22.6", - "@babel/parser": "^7.22.7", - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.8", - "@babel/types": "^7.22.5", - "convert-source-map": "^1.7.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-module-transforms": "^7.25.2", + "@babel/helpers": "^7.25.0", + "@babel/parser": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.2", + "@babel/types": "^7.25.2", + "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.2.2", + "json5": "^2.2.3", "semver": "^6.3.1" }, "engines": { @@ -331,40 +259,12 @@ "url": "https://opencollective.com/babel" } }, - "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/eslint-parser": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.22.9.tgz", - "integrity": "sha512-xdMkt39/nviO/4vpVdrEYPwXCsYIXSSAr6mC7WQsNIlGnuxKyKE7GZjalcnbSWiC4OXGNNN3UQPeHfjSC6sTDA==", - "dependencies": { - "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", - "eslint-visitor-keys": "^2.1.0", - "semver": "^6.3.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || >=14.0.0" - }, - "peerDependencies": { - "@babel/core": ">=7.11.0", - "eslint": "^7.5.0 || ^8.0.0" - } - }, - "node_modules/@babel/eslint-parser/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "engines": { - "node": ">=10" - } + "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/eslint-parser/node_modules/semver": { + "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==", @@ -373,49 +273,54 @@ } }, "node_modules/@babel/generator": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", - "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.7.tgz", + "integrity": "sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA==", + "license": "MIT", "dependencies": { - "@babel/types": "^7.23.6", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" + "@babel/types": "^7.25.7", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", - "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.7.tgz", + "integrity": "sha512-4xwU8StnqnlIhhioZf1tqnVWeQ9pvH/ujS8hRfw/WOza+/a+1qv69BWNy+oY231maTCWgKWhfBU7kDpsds6zAA==", + "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz", - "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==", + "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/types": "^7.22.15" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", - "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz", + "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==", "dependencies": { - "@babel/compat-data": "^7.23.5", - "@babel/helper-validator-option": "^7.23.5", - "browserslist": "^4.22.2", + "@babel/compat-data": "^7.25.2", + "@babel/helper-validator-option": "^7.24.8", + "browserslist": "^4.23.1", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -432,18 +337,17 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.23.10", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.10.tgz", - "integrity": "sha512-2XpP2XhkXzgxecPNEEK8Vz8Asj9aRxt08oKOqtiZoqV2UGZ5T+EkyP9sXQ9nwMxBIG34a7jmasVqoMop7VdPUw==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-member-expression-to-functions": "^7.23.0", - "@babel/helper-optimise-call-expression": "^7.22.5", - "@babel/helper-replace-supers": "^7.22.20", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.4.tgz", + "integrity": "sha512-ro/bFs3/84MDgDmMwbcHgDa8/E6J3QKNTk4xJJnVeFtGE+tL0K26E3pNxhYz2b67fJpt7Aphw5XcploKXuCvCQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^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.25.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/traverse": "^7.25.4", "semver": "^6.3.1" }, "engines": { @@ -457,16 +361,18 @@ "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/@babel/helper-create-regexp-features-plugin": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz", - "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==", + "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.22.5", + "@babel/helper-annotate-as-pure": "^7.24.7", "regexpu-core": "^5.3.1", "semver": "^6.3.1" }, @@ -481,14 +387,16 @@ "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/@babel/helper-define-polyfill-provider": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.1.tgz", - "integrity": "sha512-kX4oXixDxG197yhX+J3Wp+NpL2wuCFjWQAr6yX2jtCnflK9ulMI51ULFGIrWiX1jGfvAxdHp+XQCcP2bZGPs9A==", + "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", @@ -497,72 +405,44 @@ "resolve": "^1.14.2" }, "peerDependencies": { - "@babel/core": "^7.4.0-0" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", - "dependencies": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", - "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", + "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/types": "^7.23.0" + "@babel/traverse": "^7.24.8", + "@babel/types": "^7.24.8" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", - "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.7.tgz", + "integrity": "sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw==", + "license": "MIT", "dependencies": { - "@babel/types": "^7.22.15" + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", - "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "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==", "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.20" + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7", + "@babel/traverse": "^7.25.2" }, "engines": { "node": ">=6.9.0" @@ -572,32 +452,35 @@ } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", - "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", + "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.22.5" + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.7.tgz", + "integrity": "sha512-eaPZai0PiqCi09pPs3pAFfl/zYgGaE6IdXtYvmf0qlcDTd3WCtO7JWCcRd64e0EQrcYgiHibEZnOGsSY4QSgaw==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz", - "integrity": "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==", + "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.22.5", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-wrap-function": "^7.22.20" + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-wrap-function": "^7.25.0", + "@babel/traverse": "^7.25.0" }, "engines": { "node": ">=6.9.0" @@ -607,13 +490,14 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz", - "integrity": "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==", + "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-environment-visitor": "^7.22.20", - "@babel/helper-member-expression-to-functions": "^7.22.15", - "@babel/helper-optimise-call-expression": "^7.22.5" + "@babel/helper-member-expression-to-functions": "^7.24.8", + "@babel/helper-optimise-call-expression": "^7.24.7", + "@babel/traverse": "^7.25.0" }, "engines": { "node": ">=6.9.0" @@ -623,96 +507,93 @@ } }, "node_modules/@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "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/types": "^7.22.5" + "@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.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", - "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "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/types": "^7.22.5" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", - "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz", + "integrity": "sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz", + "integrity": "sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", - "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.7.tgz", + "integrity": "sha512-ytbPLsm+GjArDYXJ8Ydr1c/KJuutjF2besPNbIZnZ6MKUxi/uTA22t2ymmA4WFjZFpjiAMO0xuuJPqK2nvDVfQ==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz", - "integrity": "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==", + "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/helper-function-name": "^7.22.5", - "@babel/template": "^7.22.15", - "@babel/types": "^7.22.19" + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.0", + "@babel/types": "^7.25.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.6.tgz", - "integrity": "sha512-YjDs6y/fVOYFV8hAf1rxd1QvR9wJe1pDBZ2AREKq/SDayfPzgk0PBnVuTCE5X1acEpMMNOVUqoe+OwiZGJ+OaA==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.6.tgz", + "integrity": "sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q==", "dependencies": { - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.6", - "@babel/types": "^7.22.5" + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", - "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.7.tgz", + "integrity": "sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw==", + "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-validator-identifier": "^7.25.7", "chalk": "^2.4.2", - "js-tokens": "^4.0.0" + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" @@ -722,6 +603,7 @@ "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==", + "license": "MIT", "dependencies": { "color-convert": "^1.9.0" }, @@ -733,6 +615,7 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -746,6 +629,7 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", "dependencies": { "color-name": "1.1.3" } @@ -753,12 +637,14 @@ "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==" + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" }, "node_modules/@babel/highlight/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==", + "license": "MIT", "engines": { "node": ">=0.8.0" } @@ -767,6 +653,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", "engines": { "node": ">=4" } @@ -775,6 +662,7 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "license": "MIT", "dependencies": { "has-flag": "^3.0.0" }, @@ -783,9 +671,13 @@ } }, "node_modules/@babel/parser": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.0.tgz", - "integrity": "sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.8.tgz", + "integrity": "sha512-HcttkxzdPucv3nNFmfOOMfFf64KgdJVqm1KaCm25dPGMLElo9nsLvXeJECQg8UzPuBGLyTSA0ZzqCtDSzKTEoQ==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.8" + }, "bin": { "parser": "bin/babel-parser.js" }, @@ -793,12 +685,14 @@ "node": ">=6.0.0" } }, - "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.23.3", - "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.23.3.tgz", - "integrity": "sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ==", + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "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.22.5" + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.3" }, "engines": { "node": ">=6.9.0" @@ -807,29 +701,13 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.23.3.tgz", - "integrity": "sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", - "@babel/plugin-transform-optional-chaining": "^7.23.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.13.0" - } - }, - "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.23.7.tgz", - "integrity": "sha512-LlRT7HgaifEpQA1ZgLVOIJZZFVPWN5iReq/7/JixwBtwcoeVGDBD53ZV28rrsLYOZs1Y/EHhA8N/Z6aazHR8cw==", + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "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-environment-visitor": "^7.22.20", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -838,98 +716,52 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-proposal-class-properties": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", - "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-decorators": { - "version": "7.22.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.22.7.tgz", - "integrity": "sha512-omXqPF7Onq4Bb7wHxXjM3jSMSJvUUbvDvmmds7KI5n9Cq6Ln5I05I1W2nRlRof1rGdiUxJrxwe285WF96XlBXQ==", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.22.6", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-replace-supers": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/plugin-syntax-decorators": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", - "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@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-proposal-numeric-separator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", - "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "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.18.6", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-proposal-optional-chaining": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz", - "integrity": "sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==", + "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==", + "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" + "@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.0.0-0" + "@babel/core": "^7.13.0" } }, - "node_modules/@babel/plugin-proposal-private-methods": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", - "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "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-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.0" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, "node_modules/@babel/plugin-proposal-private-property-in-object": { @@ -954,6 +786,7 @@ "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" }, @@ -965,6 +798,7 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -976,6 +810,7 @@ "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" }, @@ -987,6 +822,7 @@ "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" }, @@ -997,24 +833,11 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-decorators": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.22.5.tgz", - "integrity": "sha512-avpUOBS7IU6al8MmF1XpAyj9QYeLPuSDJI5D4pVMSMdL7xQokKqJPYQC67RCT0aCTashUXPiGwMJ0DEXXCEmMA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.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==", + "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1026,6 +849,7 @@ "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" }, @@ -1033,26 +857,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-flow": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.22.5.tgz", - "integrity": "sha512-9RdCl0i+q0QExayk2nOS7853w08yLucnnPML6EN9S8fgMPVtdLDCdx/cOQ/i44Lb9UeQX9A35yaqBBOMMZxPxQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.23.3.tgz", - "integrity": "sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.25.6.tgz", + "integrity": "sha512-aABl0jHw9bZ2karQ/uUD6XP4u0SG22SJrOHFoL6XB1R7dTovOP4TzTlsxOYC5yQ1pdscVK2JTUnF6QL3ARoAiQ==", + "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -1062,11 +873,12 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.23.3.tgz", - "integrity": "sha512-pawnE0P9g10xgoP7yKr6CK63K2FMsTE+FZidZO/1PwRdzmAPVs+HS1mAURUsgaoxammTJvULUdIkEK0gOcU2tA==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.6.tgz", + "integrity": "sha512-sXaDXaJN9SNLymBdlWFA+bjzBhFD617ZaFiY13dGt7TVslVvVgA6fkZOP7Ki3IGElC45lwHdOTrCtKZGVAWeLQ==", + "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -1079,6 +891,7 @@ "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" }, @@ -1090,6 +903,7 @@ "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" }, @@ -1098,11 +912,13 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz", - "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.7.tgz", + "integrity": "sha512-ruZOnKO+ajVL/MVx+PwNBPOkrnXTXoWMtte1MBpegfCArhqOe3Bj52avVj1huLLxNKYKXYaSxZ2F+woK1ekXfw==", + "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1115,6 +931,7 @@ "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" }, @@ -1126,6 +943,7 @@ "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" }, @@ -1137,6 +955,7 @@ "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" }, @@ -1148,6 +967,7 @@ "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" }, @@ -1159,6 +979,7 @@ "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" }, @@ -1170,6 +991,7 @@ "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" }, @@ -1181,6 +1003,7 @@ "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" }, @@ -1195,6 +1018,7 @@ "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" }, @@ -1206,11 +1030,12 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz", - "integrity": "sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.4.tgz", + "integrity": "sha512-uMOCoHVU52BsSWxPOMVv5qKRdeSlPuImUCB2dlPuBSU+W2/ROE7/Zg8F2Kepbk+8yBa68LlRKxO+xgEVWorsDg==", + "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -1223,6 +1048,7 @@ "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" @@ -1235,11 +1061,12 @@ } }, "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.23.3.tgz", - "integrity": "sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ==", + "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.22.5" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1249,14 +1076,15 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.9.tgz", - "integrity": "sha512-8Q3veQEDGe14dTYuwagbRtwxQDnytyg1JFu4/HwEMETeofocrB0U0ejBJIXoeG/t2oXZ8kzCyI0ZZfbT80VFNQ==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.4.tgz", + "integrity": "sha512-jz8cV2XDDTqjKPwVPJBIjORVEmSGYhdRa8e5k5+vN+uwcjSrSxUaebBRa4ko1jqNF2uxyg8G6XYk30Jv285xzg==", + "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-remap-async-to-generator": "^7.22.20", - "@babel/plugin-syntax-async-generators": "^7.8.4" + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-remap-async-to-generator": "^7.25.0", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/traverse": "^7.25.4" }, "engines": { "node": ">=6.9.0" @@ -1266,13 +1094,14 @@ } }, "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.23.3.tgz", - "integrity": "sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw==", + "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.22.15", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-remap-async-to-generator": "^7.22.20" + "@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" @@ -1282,11 +1111,12 @@ } }, "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.23.3.tgz", - "integrity": "sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A==", + "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.22.5" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1296,11 +1126,12 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.4.tgz", - "integrity": "sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw==", + "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.22.5" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -1310,12 +1141,13 @@ } }, "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.23.3.tgz", - "integrity": "sha512-uM+AN8yCIjDPccsKGlw271xjJtGii+xQIF/uMPS8H15L12jZTsLfF4o5vNO7d/oUguOyfdikHGc/yi9ge4SGIg==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.4.tgz", + "integrity": "sha512-nZeZHyCWPfjkdU5pA/uHiTaDAFUEqkpzf1YoQT2NeSynCGYq9rxfyI3XpQbfx/a0hSnFH6TGlEXvae5Vi7GD8g==", + "dev": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-create-class-features-plugin": "^7.25.4", + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -1325,12 +1157,13 @@ } }, "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.23.4.tgz", - "integrity": "sha512-nsWu/1M+ggti1SOALj3hfx5FXzAY06fwPJsUZD4/A5e1bWi46VUIWtD+kOX6/IdhXGsXBWllLFDSnqSCdUNydQ==", + "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.22.15", - "@babel/helper-plugin-utils": "^7.22.5", + "@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": { @@ -1341,17 +1174,16 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.23.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.23.8.tgz", - "integrity": "sha512-yAYslGsY1bX6Knmg46RjiCiNSwJKv2IUC8qOdYKqMMr0491SXFhcHqOdRDeCRohOOIzwN/90C6mQ9qAKgrP7dg==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-replace-supers": "^7.22.20", - "@babel/helper-split-export-declaration": "^7.22.6", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.4.tgz", + "integrity": "sha512-oexUfaQle2pF/b6E0dwsxQtAol9TLSO88kQvym6HHBWFliV2lGdrPieX+WgMRLSJDVzdYywk7jXbLPuO2KLTLg==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-replace-supers": "^7.25.0", + "@babel/traverse": "^7.25.4", "globals": "^11.1.0" }, "engines": { @@ -1362,12 +1194,13 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.23.3.tgz", - "integrity": "sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw==", + "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.22.5", - "@babel/template": "^7.22.15" + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/template": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1377,11 +1210,12 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.23.3.tgz", - "integrity": "sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw==", + "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.22.5" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -1391,12 +1225,13 @@ } }, "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.23.3.tgz", - "integrity": "sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ==", + "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.22.15", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1406,11 +1241,12 @@ } }, "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.23.3.tgz", - "integrity": "sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA==", + "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.22.5" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1419,28 +1255,30 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.23.4.tgz", - "integrity": "sha512-V6jIbLhdJK86MaLh4Jpghi8ho5fGzt3imHOBu/x0jlBaPYqDoWz4RDXjmMOfnh+JWNaQleEAByZLV0QzBT4YQQ==", + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "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-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" + "@babel/helper-create-regexp-features-plugin": "^7.25.0", + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.23.3.tgz", - "integrity": "sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ==", + "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==", + "dev": true, "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" }, "engines": { "node": ">=6.9.0" @@ -1449,13 +1287,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.23.4.tgz", - "integrity": "sha512-GzuSBcKkx62dGzZI1WVgTWvkkz84FZO5TC5T8dl/Tht/rAla6Dg/Mz9Yhypg+ezVACf/rgDuQt3kbWEv7LdUDQ==", + "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==", + "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1464,13 +1303,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-flow-strip-types": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.22.5.tgz", - "integrity": "sha512-tujNbZdxdG0/54g/oua8ISToaXTFBf8EnSb5PgQSciIXWOWKX3S4+JR7ZE9ol8FZwf9kxitzkGQ+QWeov/mCiA==", + "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==", + "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-flow": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" }, "engines": { "node": ">=6.9.0" @@ -1480,12 +1320,13 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.23.6.tgz", - "integrity": "sha512-aYH4ytZ0qSuBbpfhuofbg/e96oQ7U2w1Aw/UQmKT+1l39uEhUPoFS3fHevDc1G0OvewyDudfMKY1OulczHzWIw==", + "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.22.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1495,13 +1336,14 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.23.3.tgz", - "integrity": "sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw==", + "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.22.15", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-compilation-targets": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.1" }, "engines": { "node": ">=6.9.0" @@ -1511,11 +1353,12 @@ } }, "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.23.4.tgz", - "integrity": "sha512-81nTOqM1dMwZ/aRXQ59zVubN9wHGqk6UtqRK+/q+ciXmRy8fSolhGVvG09HHRGo4l6fr/c4ZhXUQH0uFW7PZbg==", + "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.22.5", + "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-json-strings": "^7.8.3" }, "engines": { @@ -1526,11 +1369,12 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.23.3.tgz", - "integrity": "sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ==", + "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.22.5" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -1540,11 +1384,12 @@ } }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.23.4.tgz", - "integrity": "sha512-Mc/ALf1rmZTP4JKKEhUwiORU+vcfarFVLfcFiolKUo6sewoxSEgl36ak5t+4WamRsNr6nzjZXQjM35WsU+9vbg==", + "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.22.5", + "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" }, "engines": { @@ -1555,11 +1400,12 @@ } }, "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.23.3.tgz", - "integrity": "sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag==", + "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.22.5" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1569,12 +1415,13 @@ } }, "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.23.3.tgz", - "integrity": "sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw==", + "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.23.3", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1584,13 +1431,14 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.3.tgz", - "integrity": "sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==", + "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.23.3", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-simple-access": "^7.22.5" + "@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" @@ -1600,14 +1448,15 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.9.tgz", - "integrity": "sha512-KDlPRM6sLo4o1FkiSlXoAa8edLXFsKKIda779fbLrvmeuc3itnjCtaO6RrtoaANsIJANj+Vk1zqbZIMhkCAHVw==", + "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-hoist-variables": "^7.22.5", - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20" + "@babel/helper-module-transforms": "^7.25.0", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", + "@babel/traverse": "^7.25.0" }, "engines": { "node": ">=6.9.0" @@ -1617,12 +1466,13 @@ } }, "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.23.3.tgz", - "integrity": "sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg==", + "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.23.3", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1632,12 +1482,13 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", - "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", + "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.22.5", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1647,11 +1498,12 @@ } }, "node_modules/@babel/plugin-transform-new-target": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.23.3.tgz", - "integrity": "sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ==", + "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.22.5" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1661,11 +1513,12 @@ } }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.23.4.tgz", - "integrity": "sha512-jHE9EVVqHKAQx+VePv5LLGHjmHSJR76vawFPTdlxR/LVJPfOEGxREQwQfjuZEOPTwG92X3LINSh3M40Rv4zpVA==", + "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.22.5", + "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" }, "engines": { @@ -1676,11 +1529,12 @@ } }, "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.23.4.tgz", - "integrity": "sha512-mps6auzgwjRrwKEZA05cOwuDc9FAzoyFS4ZsG/8F43bTLf/TgkJg7QXOrPO1JO599iA3qgK9MXdMGOEC8O1h6Q==", + "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.22.5", + "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-numeric-separator": "^7.10.4" }, "engines": { @@ -1691,15 +1545,15 @@ } }, "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.23.4.tgz", - "integrity": "sha512-9x9K1YyeQVw0iOXJlIzwm8ltobIIv7j2iLyP2jIhEbqPRQ7ScNgwQufU2I0Gq11VjyG4gI4yMXt2VFags+1N3g==", + "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/compat-data": "^7.23.3", - "@babel/helper-compilation-targets": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5", + "@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.23.3" + "@babel/plugin-transform-parameters": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1709,12 +1563,13 @@ } }, "node_modules/@babel/plugin-transform-object-super": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.23.3.tgz", - "integrity": "sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA==", + "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.22.5", - "@babel/helper-replace-supers": "^7.22.20" + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-replace-supers": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1724,11 +1579,12 @@ } }, "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.23.4.tgz", - "integrity": "sha512-XIq8t0rJPHf6Wvmbn9nFxU6ao4c7WhghTR5WyV8SrJfUFzyxhCm4nhC+iAp3HFhbAKLfYpgzhJ6t4XCtVwqO5A==", + "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.22.5", + "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" }, "engines": { @@ -1739,12 +1595,13 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.23.4.tgz", - "integrity": "sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA==", + "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.22.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@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": { @@ -1755,11 +1612,12 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.23.3.tgz", - "integrity": "sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==", + "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.22.5" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1769,12 +1627,13 @@ } }, "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.23.3.tgz", - "integrity": "sha512-UzqRcRtWsDMTLrRWFvUBDwmw06tCQH9Rl1uAjfh6ijMSmGYQ+fpdB+cnqRC8EMh5tuuxSv0/TejGL+7vyj+50g==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.4.tgz", + "integrity": "sha512-ao8BG7E2b/URaUQGqN3Tlsg+M3KlHY6rJ1O1gXAEUnZoyNQnvKyH87Kfg+FoxSeyWUB8ISZZsC91C44ZuBFytw==", + "dev": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-create-class-features-plugin": "^7.25.4", + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -1784,13 +1643,14 @@ } }, "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.23.4.tgz", - "integrity": "sha512-9G3K1YqTq3F4Vt88Djx1UZ79PDyj+yKRnUy7cZGSMe+a7jkwD259uKKuUzQlPkGam7R+8RJwh5z4xO27fA1o2A==", + "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.22.5", - "@babel/helper-create-class-features-plugin": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5", + "@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": { @@ -1801,11 +1661,12 @@ } }, "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.23.3.tgz", - "integrity": "sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw==", + "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.22.5" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1814,12 +1675,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-react-constant-elements": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.22.5.tgz", - "integrity": "sha512-BF5SXoO+nX3h5OhlN78XbbDrBOffv+AxPP2ENaJOVqjWCgBDeOY3WcaUcddutGSfoap+5NEQ/q/4I3WZIvgkXA==", + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.25.7.tgz", + "integrity": "sha512-r0QY7NVU8OnrwE+w2IWiRom0wwsTbjx4+xH2RTd7AVdof3uurXOF+/mXHQDRk+2jIvWgSaCHKMgggfvM4dyUGA==", + "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1828,12 +1691,18 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-react-display-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.22.5.tgz", - "integrity": "sha512-PVk3WPYudRF5z4GKMEYUrLjPl38fJSKNaEOkFuoprioowGuWN6w2RKznuFNSlJx7pzzXXStPUnNSOEO0jL5EVw==", + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.7.tgz", + "integrity": "sha512-vILAg5nwGlR9EXE8JIOX4NHXd49lrYbN8hnjffDtoULwpL9hUx/N55nqh2qd0q6FyNDfjl9V79ecKGvFbcSA0Q==", + "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-annotate-as-pure": "^7.25.7", + "@babel/helper-module-imports": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/plugin-syntax-jsx": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1842,16 +1711,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.22.5.tgz", - "integrity": "sha512-rog5gZaVbUip5iWDMTYbVM15XQq+RkUKhET/IHR6oizR+JEoN6CAfTTuHcK4vwUyzca30qqHqEpzBOnaRMWYMA==", + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.25.7.tgz", + "integrity": "sha512-5yd3lH1PWxzW6IZj+p+Y4OLQzz0/LzlOG8vGqonHfVR3euf1vyzyMUJk9Ac+m97BH46mFc/98t9PmYLyvgL3qg==", + "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-module-imports": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-jsx": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/plugin-transform-react-jsx": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1860,12 +1727,12 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-react-jsx-development": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.22.5.tgz", - "integrity": "sha512-bDhuzwWMuInwCYeDeMzyi7TaBgRQei6DqxhbyniL7/VG4RSS7HtSL2QbY4eESy1KJqlWt8g3xeEBGPuo+XqC8A==", + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.24.7.tgz", + "integrity": "sha512-fOPQYbGSgH0HUp4UJO4sMBFjY6DuWq+2i8rixyUMb3CdGixs/gccURvYOAhajBdKDoGajFr3mUq5rH3phtkGzw==", "dependencies": { - "@babel/plugin-transform-react-jsx": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1874,13 +1741,12 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-react-pure-annotations": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.22.5.tgz", - "integrity": "sha512-gP4k85wx09q+brArVinTXhWiyzLl9UpmGva0+mWyKxk6JZequ05x3eUcIUE+FyttPKJFRRVtAvQaJ6YF9h1ZpA==", + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.24.7.tgz", + "integrity": "sha512-J2z+MWzZHVOemyLweMqngXrgGC42jQ//R0KdxqkIz/OrbVIIlhFI3WigZ5fO+nwFvBlncr4MGapd8vTyc7RPNQ==", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1889,13 +1755,15 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.23.3.tgz", - "integrity": "sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==", + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.25.7.tgz", + "integrity": "sha512-6YTHJ7yjjgYqGc8S+CbEXhLICODk0Tn92j+vNJo07HFk9t3bjFgAKxPLFhHwF2NjmQVSI1zBRfBWUeVBa2osfA==", + "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "regenerator-transform": "^0.15.2" + "@babel/helper-annotate-as-pure": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1904,12 +1772,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.23.3.tgz", - "integrity": "sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg==", + "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==", + "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.7", + "regenerator-transform": "^0.15.2" }, "engines": { "node": ">=6.9.0" @@ -1918,17 +1788,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-runtime": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.22.9.tgz", - "integrity": "sha512-9KjBH61AGJetCPYp/IEyLEp47SyybZb0nDRpBvmtEkm+rUIwxdlKpyNHI1TmsGkeuLclJdleQHRZ8XLBnnh8CQ==", + "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==", + "dev": true, "dependencies": { - "@babel/helper-module-imports": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5", - "babel-plugin-polyfill-corejs2": "^0.4.4", - "babel-plugin-polyfill-corejs3": "^0.8.2", - "babel-plugin-polyfill-regenerator": "^0.5.1", - "semver": "^6.3.1" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1937,20 +1803,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-runtime/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-transform-shorthand-properties": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.23.3.tgz", - "integrity": "sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg==", + "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.22.5" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1960,12 +1819,13 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.23.3.tgz", - "integrity": "sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg==", + "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.22.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1975,11 +1835,12 @@ } }, "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.23.3.tgz", - "integrity": "sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg==", + "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.22.5" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1989,11 +1850,12 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.23.3.tgz", - "integrity": "sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg==", + "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.22.5" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2003,11 +1865,12 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.23.3.tgz", - "integrity": "sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ==", + "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.22.5" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -2017,14 +1880,16 @@ } }, "node_modules/@babel/plugin-transform-typescript": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.23.6.tgz", - "integrity": "sha512-6cBG5mBvUu4VUD04OHKnYzbuHNP8huDsD3EDqqpIpsswTDoqHCjLoHb6+QgsV1WsT2nipRqCPgxD3LXnEO7XfA==", + "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.22.5", - "@babel/helper-create-class-features-plugin": "^7.23.6", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-typescript": "^7.23.3" + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-create-class-features-plugin": "^7.25.0", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/plugin-syntax-typescript": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2034,11 +1899,12 @@ } }, "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.23.3.tgz", - "integrity": "sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q==", + "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.22.5" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2048,12 +1914,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.23.3.tgz", - "integrity": "sha512-KcLIm+pDZkWZQAFJ9pdfmh89EwVfmNovFBcXko8szpBeF8z68kWIPeKlmSOkT9BXJxs2C0uk+5LxoxIv62MROA==", + "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.22.15", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2063,12 +1930,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.23.3.tgz", - "integrity": "sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw==", + "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.22.15", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2078,12 +1946,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.23.3.tgz", - "integrity": "sha512-W7lliA/v9bNR83Qc3q1ip9CQMZ09CcHDbHfbLRDNuAhn1Mvkr1ZNF7hPmztMQvtTGVLJ9m8IZqWsTkXOml8dbw==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.4.tgz", + "integrity": "sha512-qesBxiWkgN1Q+31xUE9RcMk79eOXXDCv6tfyGMRSs4RGlioSg2WVyQAm07k726cSE56pa+Kb0y9epX2qaXzTvA==", + "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-create-regexp-features-plugin": "^7.25.2", + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -2093,25 +1962,28 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.9.tgz", - "integrity": "sha512-3kBGTNBBk9DQiPoXYS0g0BYlwTQYUTifqgKTjxUwEUkduRT2QOa0FPGBJ+NROQhGyYO5BuTJwGvBnqKDykac6A==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.25.4.tgz", + "integrity": "sha512-W9Gyo+KmcxjGahtt3t9fb14vFRWvPpu5pT6GBlovAK6BTBcxgjfVMSQCfJl4oi35ODrxP6xx2Wr8LNST57Mraw==", + "dev": true, "dependencies": { - "@babel/compat-data": "^7.23.5", - "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-validator-option": "^7.23.5", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.23.3", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.23.3", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.23.7", + "@babel/compat-data": "^7.25.4", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-validator-option": "^7.24.8", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.3", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.0", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.0", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.7", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.0", "@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.23.3", - "@babel/plugin-syntax-import-attributes": "^7.23.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", @@ -2123,59 +1995,60 @@ "@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.23.3", - "@babel/plugin-transform-async-generator-functions": "^7.23.9", - "@babel/plugin-transform-async-to-generator": "^7.23.3", - "@babel/plugin-transform-block-scoped-functions": "^7.23.3", - "@babel/plugin-transform-block-scoping": "^7.23.4", - "@babel/plugin-transform-class-properties": "^7.23.3", - "@babel/plugin-transform-class-static-block": "^7.23.4", - "@babel/plugin-transform-classes": "^7.23.8", - "@babel/plugin-transform-computed-properties": "^7.23.3", - "@babel/plugin-transform-destructuring": "^7.23.3", - "@babel/plugin-transform-dotall-regex": "^7.23.3", - "@babel/plugin-transform-duplicate-keys": "^7.23.3", - "@babel/plugin-transform-dynamic-import": "^7.23.4", - "@babel/plugin-transform-exponentiation-operator": "^7.23.3", - "@babel/plugin-transform-export-namespace-from": "^7.23.4", - "@babel/plugin-transform-for-of": "^7.23.6", - "@babel/plugin-transform-function-name": "^7.23.3", - "@babel/plugin-transform-json-strings": "^7.23.4", - "@babel/plugin-transform-literals": "^7.23.3", - "@babel/plugin-transform-logical-assignment-operators": "^7.23.4", - "@babel/plugin-transform-member-expression-literals": "^7.23.3", - "@babel/plugin-transform-modules-amd": "^7.23.3", - "@babel/plugin-transform-modules-commonjs": "^7.23.3", - "@babel/plugin-transform-modules-systemjs": "^7.23.9", - "@babel/plugin-transform-modules-umd": "^7.23.3", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", - "@babel/plugin-transform-new-target": "^7.23.3", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.23.4", - "@babel/plugin-transform-numeric-separator": "^7.23.4", - "@babel/plugin-transform-object-rest-spread": "^7.23.4", - "@babel/plugin-transform-object-super": "^7.23.3", - "@babel/plugin-transform-optional-catch-binding": "^7.23.4", - "@babel/plugin-transform-optional-chaining": "^7.23.4", - "@babel/plugin-transform-parameters": "^7.23.3", - "@babel/plugin-transform-private-methods": "^7.23.3", - "@babel/plugin-transform-private-property-in-object": "^7.23.4", - "@babel/plugin-transform-property-literals": "^7.23.3", - "@babel/plugin-transform-regenerator": "^7.23.3", - "@babel/plugin-transform-reserved-words": "^7.23.3", - "@babel/plugin-transform-shorthand-properties": "^7.23.3", - "@babel/plugin-transform-spread": "^7.23.3", - "@babel/plugin-transform-sticky-regex": "^7.23.3", - "@babel/plugin-transform-template-literals": "^7.23.3", - "@babel/plugin-transform-typeof-symbol": "^7.23.3", - "@babel/plugin-transform-unicode-escapes": "^7.23.3", - "@babel/plugin-transform-unicode-property-regex": "^7.23.3", - "@babel/plugin-transform-unicode-regex": "^7.23.3", - "@babel/plugin-transform-unicode-sets-regex": "^7.23.3", + "@babel/plugin-transform-arrow-functions": "^7.24.7", + "@babel/plugin-transform-async-generator-functions": "^7.25.4", + "@babel/plugin-transform-async-to-generator": "^7.24.7", + "@babel/plugin-transform-block-scoped-functions": "^7.24.7", + "@babel/plugin-transform-block-scoping": "^7.25.0", + "@babel/plugin-transform-class-properties": "^7.25.4", + "@babel/plugin-transform-class-static-block": "^7.24.7", + "@babel/plugin-transform-classes": "^7.25.4", + "@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-duplicate-named-capturing-groups-regex": "^7.25.0", + "@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.25.1", + "@babel/plugin-transform-json-strings": "^7.24.7", + "@babel/plugin-transform-literals": "^7.25.2", + "@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.25.0", + "@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.25.4", + "@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.25.4", "@babel/preset-modules": "0.1.6-no-external-plugins", - "babel-plugin-polyfill-corejs2": "^0.4.8", - "babel-plugin-polyfill-corejs3": "^0.9.0", - "babel-plugin-polyfill-regenerator": "^0.5.5", - "core-js-compat": "^3.31.0", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.6", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "core-js-compat": "^3.37.1", "semver": "^6.3.1" }, "engines": { @@ -2185,25 +2058,11 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/preset-env/node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.5.0.tgz", - "integrity": "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q==", - "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/preset-env/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==", + "dev": true, "engines": { "node": ">=6.9.0" }, @@ -2211,22 +2070,11 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/preset-env/node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.9.0.tgz", - "integrity": "sha512-7nZPG1uzK2Ymhy/NbaOWTg3uibM2BmGASS4vHS4szRZAIR8R6GwA/xAujpdrXU5iyklrimWnLWU+BLF9suPTqg==", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.5.0", - "core-js-compat": "^3.34.0" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.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==", + "dev": true, "bin": { "semver": "bin/semver.js" } @@ -2235,6 +2083,7 @@ "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", @@ -2245,16 +2094,18 @@ } }, "node_modules/@babel/preset-react": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.22.5.tgz", - "integrity": "sha512-M+Is3WikOpEJHgR385HbuCITPTaPRaNkibTEa9oiofmJvIsrceb4yp9RL9Kb+TE8LznmeyZqpP+Lopwcx59xPQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.25.7.tgz", + "integrity": "sha512-GjV0/mUEEXpi1U5ZgDprMRRgajGMRW3G5FjMr5KLKD8nT2fTG8+h/klV3+6Dm5739QE+K5+2e91qFKAYI3pmRg==", + "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-validator-option": "^7.22.5", - "@babel/plugin-transform-react-display-name": "^7.22.5", - "@babel/plugin-transform-react-jsx": "^7.22.5", - "@babel/plugin-transform-react-jsx-development": "^7.22.5", - "@babel/plugin-transform-react-pure-annotations": "^7.22.5" + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-validator-option": "^7.25.7", + "@babel/plugin-transform-react-display-name": "^7.25.7", + "@babel/plugin-transform-react-jsx": "^7.25.7", + "@babel/plugin-transform-react-jsx-development": "^7.25.7", + "@babel/plugin-transform-react-pure-annotations": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -2264,15 +2115,16 @@ } }, "node_modules/@babel/preset-typescript": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.23.3.tgz", - "integrity": "sha512-17oIGVlqz6CchO9RFYn5U6ZpWRZIngayYCtrPRSgANSwC2V1Jb+iP74nVxzzXJte8b8BYxrL1yY96xfhTBrNNQ==", + "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.22.5", - "@babel/helper-validator-option": "^7.22.15", - "@babel/plugin-syntax-jsx": "^7.23.3", - "@babel/plugin-transform-modules-commonjs": "^7.23.3", - "@babel/plugin-transform-typescript": "^7.23.3" + "@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" @@ -2284,12 +2136,13 @@ "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==" + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", + "dev": true }, "node_modules/@babel/runtime": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.6.tgz", - "integrity": "sha512-Ja18XcETdEl5mzzACGd+DKgaGJzPTCow7EglgwTmHdwokzDFYh/MHua6lU6DV/hjF2IaOJ4oX2nqnjG7RElKOw==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz", + "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -2297,50 +2150,36 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/runtime-corejs3": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.22.6.tgz", - "integrity": "sha512-M+37LLIRBTEVjktoJjbw4KVhupF0U/3PYUCbBwgAd9k17hoKhRu1n935QiG7Tuxv0LJOMrb2vuKEeYUlv0iyiw==", - "dev": true, - "dependencies": { - "core-js-pure": "^3.30.2", - "regenerator-runtime": "^0.13.11" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/runtime/node_modules/regenerator-runtime": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" }, "node_modules/@babel/template": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.23.9.tgz", - "integrity": "sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.7.tgz", + "integrity": "sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA==", + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.23.5", - "@babel/parser": "^7.23.9", - "@babel/types": "^7.23.9" + "@babel/code-frame": "^7.25.7", + "@babel/parser": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.0.tgz", - "integrity": "sha512-HfuJlI8qq3dEDmNU5ChzzpZRWq+oxCZQyMzIMEqLho+AQnhMnKQUzH6ydo3RBl/YjPCuk68Y6s0Gx0AeyULiWw==", - "dependencies": { - "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.6", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.24.0", - "@babel/types": "^7.24.0", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.7.tgz", + "integrity": "sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.25.7", + "@babel/generator": "^7.25.7", + "@babel/parser": "^7.25.7", + "@babel/template": "^7.25.7", + "@babel/types": "^7.25.7", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -2349,12 +2188,13 @@ } }, "node_modules/@babel/types": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", - "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.8.tgz", + "integrity": "sha512-JWtuCu8VQsMladxVz/P4HzHUGCAwpuqacmowgXFs5XjxIgKuNjnLokQzuVjlTvIzODaDmpjT3oxcC48vyk9EWg==", + "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.23.4", - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-string-parser": "^7.25.7", + "@babel/helper-validator-identifier": "^7.25.7", "to-fast-properties": "^2.0.0" }, "engines": { @@ -2364,410 +2204,151 @@ "node_modules/@bcoe/v8-coverage": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==" - }, - "node_modules/@csstools/normalize.css": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-12.0.0.tgz", - "integrity": "sha512-M0qqxAcwCsIVfpFQSlGN5XjXWu8l5JDZN+fPt1LeW5SZexQTgnaEvgXAY+CeygRw0EeppWHi12JxESWiWrB0Sg==" + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true }, - "node_modules/@csstools/postcss-cascade-layers": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.1.1.tgz", - "integrity": "sha512-+KdYrpKC5TgomQr2DlZF4lDEpHcoxnj5IGddYYfBWJAKfj1JtuHUIqMa+E1pJJ+z3kvDViWMqyqPlG4Ja7amQA==", - "dependencies": { - "@csstools/selector-specificity": "^2.0.2", - "postcss-selector-parser": "^6.0.10" - }, + "node_modules/@dicebear/adventurer": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@dicebear/adventurer/-/adventurer-8.0.2.tgz", + "integrity": "sha512-xBJDe8TijYCfUstgMETGAt3eXruMpwiDjbu8HdXDDOGyyHRjS2gIj4berQBhBp2kPSw++uUNuDou3eH/9MpaUQ==", + "license": "MIT", "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "node": ">=16.0.0" }, "peerDependencies": { - "postcss": "^8.2" + "@dicebear/core": "^8.0.0" } }, - "node_modules/@csstools/postcss-color-function": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-1.1.1.tgz", - "integrity": "sha512-Bc0f62WmHdtRDjf5f3e2STwRAl89N2CLb+9iAwzrv4L2hncrbDwnQD9PCq0gtAt7pOI2leIV08HIBUd4jxD8cw==", - "dependencies": { - "@csstools/postcss-progressive-custom-properties": "^1.1.0", - "postcss-value-parser": "^4.2.0" - }, + "node_modules/@dicebear/adventurer-neutral": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@dicebear/adventurer-neutral/-/adventurer-neutral-8.0.2.tgz", + "integrity": "sha512-7RpqZKzft4DBg5qNEOmU2Sz7O4HLXSTCUQ+Bmym9n5Hni+U/gjmTiUL6DtL5OhOoCz/5tG1hignzk9fdF8I9GA==", + "license": "MIT", "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "node": ">=16.0.0" }, "peerDependencies": { - "postcss": "^8.2" + "@dicebear/core": "^8.0.0" } }, - "node_modules/@csstools/postcss-font-format-keywords": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-1.0.1.tgz", - "integrity": "sha512-ZgrlzuUAjXIOc2JueK0X5sZDjCtgimVp/O5CEqTcs5ShWBa6smhWYbS0x5cVc/+rycTDbjjzoP0KTDnUneZGOg==", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, + "node_modules/@dicebear/avataaars": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@dicebear/avataaars/-/avataaars-8.0.2.tgz", + "integrity": "sha512-ezrKvE4ma7Kmzu2u8nC39exwBlOfrqmrTYuHpND1Sfem6XMborZhlGd382+35ellTMCJE5HCyN2VnZ0HWikzvQ==", + "license": "MIT", "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "node": ">=16.0.0" }, "peerDependencies": { - "postcss": "^8.2" + "@dicebear/core": "^8.0.0" } }, - "node_modules/@csstools/postcss-hwb-function": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-1.0.2.tgz", - "integrity": "sha512-YHdEru4o3Rsbjmu6vHy4UKOXZD+Rn2zmkAmLRfPet6+Jz4Ojw8cbWxe1n42VaXQhD3CQUXXTooIy8OkVbUcL+w==", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, + "node_modules/@dicebear/avataaars-neutral": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@dicebear/avataaars-neutral/-/avataaars-neutral-8.0.2.tgz", + "integrity": "sha512-T+HFETXKpk6gsW0x6t2w+gWnuQqVSw5EDCkTe4Lde5pWX4xAqYYzz7SV8fwvQGuY9RJig4UQ8LOaDwYr3vVdnw==", + "license": "MIT", "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "node": ">=16.0.0" }, "peerDependencies": { - "postcss": "^8.2" + "@dicebear/core": "^8.0.0" } }, - "node_modules/@csstools/postcss-ic-unit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-1.0.1.tgz", - "integrity": "sha512-Ot1rcwRAaRHNKC9tAqoqNZhjdYBzKk1POgWfhN4uCOE47ebGcLRqXjKkApVDpjifL6u2/55ekkpnFcp+s/OZUw==", - "dependencies": { - "@csstools/postcss-progressive-custom-properties": "^1.1.0", - "postcss-value-parser": "^4.2.0" - }, + "node_modules/@dicebear/big-ears": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@dicebear/big-ears/-/big-ears-8.0.2.tgz", + "integrity": "sha512-pFm6oJkl1gjwpNEyn+kOgyQO0bNh+6ei+S5iMiNRAnPdJ6kwEW1YXDmPIF5Aq9Xlj2FxrxRMSNI+rh4iU9mJ4Q==", + "license": "MIT", "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "node": ">=16.0.0" }, "peerDependencies": { - "postcss": "^8.2" + "@dicebear/core": "^8.0.0" } }, - "node_modules/@csstools/postcss-is-pseudo-class": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-2.0.7.tgz", - "integrity": "sha512-7JPeVVZHd+jxYdULl87lvjgvWldYu+Bc62s9vD/ED6/QTGjy0jy0US/f6BG53sVMTBJ1lzKZFpYmofBN9eaRiA==", - "dependencies": { - "@csstools/selector-specificity": "^2.0.0", - "postcss-selector-parser": "^6.0.10" - }, + "node_modules/@dicebear/big-ears-neutral": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@dicebear/big-ears-neutral/-/big-ears-neutral-8.0.2.tgz", + "integrity": "sha512-PPm1ZciS4jnrwD2btBVgJy3cffqZjwvIJJx7kGpw5vke4uks8bXmGyB1vJKftWfN6WkCvjdFbTdW8qx6NPUlBw==", + "license": "MIT", "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "node": ">=16.0.0" }, "peerDependencies": { - "postcss": "^8.2" + "@dicebear/core": "^8.0.0" } }, - "node_modules/@csstools/postcss-nested-calc": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-nested-calc/-/postcss-nested-calc-1.0.0.tgz", - "integrity": "sha512-JCsQsw1wjYwv1bJmgjKSoZNvf7R6+wuHDAbi5f/7MbFhl2d/+v+TvBTU4BJH3G1X1H87dHl0mh6TfYogbT/dJQ==", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, + "node_modules/@dicebear/big-smile": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@dicebear/big-smile/-/big-smile-8.0.2.tgz", + "integrity": "sha512-vFGSYdZE7Rw3sGbl0JsUK+rSERAuXvMIoYmzwGgIWPwGkTd9/SlxemdFLZW849Nz1FfLjxtSpUyy/slgo6WpWg==", + "license": "MIT", "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "node": ">=16.0.0" }, "peerDependencies": { - "postcss": "^8.2" + "@dicebear/core": "^8.0.0" } }, - "node_modules/@csstools/postcss-normalize-display-values": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-1.0.1.tgz", - "integrity": "sha512-jcOanIbv55OFKQ3sYeFD/T0Ti7AMXc9nM1hZWu8m/2722gOTxFg7xYu4RDLJLeZmPUVQlGzo4jhzvTUq3x4ZUw==", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, + "node_modules/@dicebear/bottts": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@dicebear/bottts/-/bottts-8.0.2.tgz", + "integrity": "sha512-0Mp0g0nChHaqr0Fz00dAX1fCTGMVimYecn4oXhZgNkCHS75SkIpepVtTASLkVGOHLHe58rAIPdOoOgqWw4wW8A==", + "license": "MIT", "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "node": ">=16.0.0" }, "peerDependencies": { - "postcss": "^8.2" + "@dicebear/core": "^8.0.0" } }, - "node_modules/@csstools/postcss-oklab-function": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-1.1.1.tgz", - "integrity": "sha512-nJpJgsdA3dA9y5pgyb/UfEzE7W5Ka7u0CX0/HIMVBNWzWemdcTH3XwANECU6anWv/ao4vVNLTMxhiPNZsTK6iA==", - "dependencies": { - "@csstools/postcss-progressive-custom-properties": "^1.1.0", - "postcss-value-parser": "^4.2.0" - }, + "node_modules/@dicebear/bottts-neutral": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@dicebear/bottts-neutral/-/bottts-neutral-8.0.2.tgz", + "integrity": "sha512-khiccnWoo0ivb+3PyneuWcL4bJc9+izAFFKIXvE3h7ozOT6VCT4h2WtYULaPwDYBAr85CygxgdWKd7aAujK6JQ==", + "license": "MIT", "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "node": ">=16.0.0" }, "peerDependencies": { - "postcss": "^8.2" - } - }, - "node_modules/@csstools/postcss-progressive-custom-properties": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-1.3.0.tgz", - "integrity": "sha512-ASA9W1aIy5ygskZYuWams4BzafD12ULvSypmaLJT2jvQ8G0M3I8PRQhC0h7mG0Z3LI05+agZjqSR9+K9yaQQjA==", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.3" - } - }, - "node_modules/@csstools/postcss-stepped-value-functions": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-1.0.1.tgz", - "integrity": "sha512-dz0LNoo3ijpTOQqEJLY8nyaapl6umbmDcgj4AD0lgVQ572b2eqA1iGZYTTWhrcrHztWDDRAX2DGYyw2VBjvCvQ==", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" - } - }, - "node_modules/@csstools/postcss-text-decoration-shorthand": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-1.0.0.tgz", - "integrity": "sha512-c1XwKJ2eMIWrzQenN0XbcfzckOLLJiczqy+YvfGmzoVXd7pT9FfObiSEfzs84bpE/VqfpEuAZ9tCRbZkZxxbdw==", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" - } - }, - "node_modules/@csstools/postcss-trigonometric-functions": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-1.0.2.tgz", - "integrity": "sha512-woKaLO///4bb+zZC2s80l+7cm07M7268MsyG3M0ActXXEFi6SuhvriQYcb58iiKGbjwwIU7n45iRLEHypB47Og==", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" - } - }, - "node_modules/@csstools/postcss-unset-value": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-1.0.2.tgz", - "integrity": "sha512-c8J4roPBILnelAsdLr4XOAR/GsTm0GJi4XpcfvoWk3U6KiTCqiFYc63KhRMQQX35jYMp4Ao8Ij9+IZRgMfJp1g==", - "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" - } - }, - "node_modules/@csstools/selector-specificity": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.2.0.tgz", - "integrity": "sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw==", - "engines": { - "node": "^14 || ^16 || >=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss-selector-parser": "^6.0.10" - } - }, - "node_modules/@dicebear/adventurer": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@dicebear/adventurer/-/adventurer-8.0.1.tgz", - "integrity": "sha512-dlEycOH+yETbNo3EtswFJCnG02OEgpyPpOFmSgUuRhcRKsqbMlcsiYV4wKeRvq6VvudJXp8UiHwWszLjCHTvKA==", - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@dicebear/core": "^8.0.0" - } - }, - "node_modules/@dicebear/adventurer-neutral": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@dicebear/adventurer-neutral/-/adventurer-neutral-8.0.1.tgz", - "integrity": "sha512-NgSz01T/K6MJn93Lk8rKPGKTx6cJe4/lNKMKjRM+4mez8S56WNdGDGUn/QY5GL3P1p01QAOMFF3hygJk3WAr3g==", - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@dicebear/core": "^8.0.0" - } - }, - "node_modules/@dicebear/avataaars": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@dicebear/avataaars/-/avataaars-8.0.1.tgz", - "integrity": "sha512-TYXqP9mq3yHOdLlJr8saXnvxj14eY2YAmoVVbT15Rp5+kPzGDyfblNsM838sP5K6JyCNeojZsGE/sPJKk/G+mA==", - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@dicebear/core": "^8.0.0" - } - }, - "node_modules/@dicebear/avataaars-neutral": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@dicebear/avataaars-neutral/-/avataaars-neutral-8.0.1.tgz", - "integrity": "sha512-vMV1Htaqpnz+qAVyn2tJWbRQIa6mpO/bu7dD0dumuIb45+LIpNwdUuCvkIQw2qf5ODhn1WAfYX3HEJaxRZc4lA==", - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@dicebear/core": "^8.0.0" - } - }, - "node_modules/@dicebear/big-ears": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@dicebear/big-ears/-/big-ears-8.0.1.tgz", - "integrity": "sha512-lnPRFbXsHv2EXJR2OLqJdoUIrSVUpf1z4GkCOfAi01sYNYVpfnzg3kNF77QUhkXUhaONF7d4Wz8rUduBHRtjaA==", - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@dicebear/core": "^8.0.0" - } - }, - "node_modules/@dicebear/big-ears-neutral": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@dicebear/big-ears-neutral/-/big-ears-neutral-8.0.1.tgz", - "integrity": "sha512-2FPvNpLI/ald3P8iWhX7SR986B8/DQlvrTNK/v+V0HRJvG1t6/7f9qfUL7OLf6plL7EgSUmKfMKacdiR5skZkA==", - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@dicebear/core": "^8.0.0" - } - }, - "node_modules/@dicebear/big-smile": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@dicebear/big-smile/-/big-smile-8.0.1.tgz", - "integrity": "sha512-uh7FP0RgX8Qtr5zpeKUSNq028IQ3srF5LHJfQGjf4wA8R+ln/Sq0gPRJk6qMCCvPFV42b7A6f7rO7mHGnQ+qDA==", - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@dicebear/core": "^8.0.0" - } - }, - "node_modules/@dicebear/bottts": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@dicebear/bottts/-/bottts-8.0.1.tgz", - "integrity": "sha512-WmaGZnKAT90EP/pzfUox22RshCk3GLB/p+6SsjD0ZIBNjcMXhaJroSoGVcHmPgQVzZBDIdW9C0qDKhkCNVVizg==", - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@dicebear/core": "^8.0.0" - } - }, - "node_modules/@dicebear/bottts-neutral": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@dicebear/bottts-neutral/-/bottts-neutral-8.0.1.tgz", - "integrity": "sha512-krbD3U+UvzlY+kfQDpg9Hql1xJmmu3y9ensiU+XZXiuNw/ZavgGqpJtzpbYeF3J5GsggQlbBh/ZAK9AIKz7S3Q==", - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@dicebear/core": "^8.0.0" + "@dicebear/core": "^8.0.0" } }, "node_modules/@dicebear/collection": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@dicebear/collection/-/collection-8.0.1.tgz", - "integrity": "sha512-RlWvOOXTxqP1llNzWhrnm6wCMKFAku/Ty0YJNv+4LYA1YIDpyLNN2PwxxCuj7hU244qUwQcVPQPPPr0XQ+rA/g==", - "dependencies": { - "@dicebear/adventurer": "8.0.1", - "@dicebear/adventurer-neutral": "8.0.1", - "@dicebear/avataaars": "8.0.1", - "@dicebear/avataaars-neutral": "8.0.1", - "@dicebear/big-ears": "8.0.1", - "@dicebear/big-ears-neutral": "8.0.1", - "@dicebear/big-smile": "8.0.1", - "@dicebear/bottts": "8.0.1", - "@dicebear/bottts-neutral": "8.0.1", - "@dicebear/croodles": "8.0.1", - "@dicebear/croodles-neutral": "8.0.1", - "@dicebear/fun-emoji": "8.0.1", - "@dicebear/icons": "8.0.1", - "@dicebear/identicon": "8.0.1", - "@dicebear/initials": "8.0.1", - "@dicebear/lorelei": "8.0.1", - "@dicebear/lorelei-neutral": "8.0.1", - "@dicebear/micah": "8.0.1", - "@dicebear/miniavs": "8.0.1", - "@dicebear/notionists": "8.0.1", - "@dicebear/notionists-neutral": "8.0.1", - "@dicebear/open-peeps": "8.0.1", - "@dicebear/personas": "8.0.1", - "@dicebear/pixel-art": "8.0.1", - "@dicebear/pixel-art-neutral": "8.0.1", - "@dicebear/rings": "8.0.1", - "@dicebear/shapes": "8.0.1", - "@dicebear/thumbs": "8.0.1" + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@dicebear/collection/-/collection-8.0.2.tgz", + "integrity": "sha512-s8PW5yxjm5MxeLnHJV13fMT9IolsnaFipM6gaBoNyGs9T+krxqlAoRVy+4mES2KmaPKVUyBLdETrAUzSpGnxmQ==", + "license": "MIT", + "dependencies": { + "@dicebear/adventurer": "8.0.2", + "@dicebear/adventurer-neutral": "8.0.2", + "@dicebear/avataaars": "8.0.2", + "@dicebear/avataaars-neutral": "8.0.2", + "@dicebear/big-ears": "8.0.2", + "@dicebear/big-ears-neutral": "8.0.2", + "@dicebear/big-smile": "8.0.2", + "@dicebear/bottts": "8.0.2", + "@dicebear/bottts-neutral": "8.0.2", + "@dicebear/croodles": "8.0.2", + "@dicebear/croodles-neutral": "8.0.2", + "@dicebear/fun-emoji": "8.0.2", + "@dicebear/icons": "8.0.2", + "@dicebear/identicon": "8.0.2", + "@dicebear/initials": "8.0.2", + "@dicebear/lorelei": "8.0.2", + "@dicebear/lorelei-neutral": "8.0.2", + "@dicebear/micah": "8.0.2", + "@dicebear/miniavs": "8.0.2", + "@dicebear/notionists": "8.0.2", + "@dicebear/notionists-neutral": "8.0.2", + "@dicebear/open-peeps": "8.0.2", + "@dicebear/personas": "8.0.2", + "@dicebear/pixel-art": "8.0.2", + "@dicebear/pixel-art-neutral": "8.0.2", + "@dicebear/rings": "8.0.2", + "@dicebear/shapes": "8.0.2", + "@dicebear/thumbs": "8.0.2" }, "engines": { "node": ">=16.0.0" @@ -2777,9 +2358,9 @@ } }, "node_modules/@dicebear/converter": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@dicebear/converter/-/converter-8.0.1.tgz", - "integrity": "sha512-65L04fN4V07WcUnwQuDYDH+zrP8WA6/UeIuqqH/Pv7VWoJtIk9qHlaA+XGpPr4qgRtkmY7uXVkrED/RMlqvUDA==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@dicebear/converter/-/converter-8.0.2.tgz", + "integrity": "sha512-mREmyQLIfHnt30Xzjc9ZHgDgIzbF7BXApBCYolnB2kO2Kpb14OdmsyLRsYe/Tt+Vt6sLgiigWoZFcRvbStRhLA==", "dependencies": { "@types/json-schema": "^7.0.11", "tmp-promise": "^3.0.3" @@ -2805,11 +2386,11 @@ } }, "node_modules/@dicebear/core": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@dicebear/core/-/core-8.0.1.tgz", - "integrity": "sha512-HWqvQRpVjkboQXinCOjU3poZIMd5p+32wPvc9N5fYiXe3KQLhJNw5T5XiRttDUm3XpoTvhQ4DVTPDsXT8CqrTg==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@dicebear/core/-/core-8.0.2.tgz", + "integrity": "sha512-Zr3dBAH+6BBYc2kjz7KvJCMYasQlsY9CZ7D3abgZhk/XRT4B3qxo8kP+FL8YjJvrOJyV2P7h08BAKZlTWuKXPA==", "dependencies": { - "@dicebear/converter": "8.0.1", + "@dicebear/converter": "8.0.2", "@types/json-schema": "^7.0.11" }, "engines": { @@ -2817,9 +2398,10 @@ } }, "node_modules/@dicebear/croodles": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@dicebear/croodles/-/croodles-8.0.1.tgz", - "integrity": "sha512-4si6gm61hEI8uDk+7OhSX+0qSPfotYx1dbdBphgGgiP9KTOgipnXzNtz8YnGzNf+V89nV4twHa6Bl6Wna4kFYA==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@dicebear/croodles/-/croodles-8.0.2.tgz", + "integrity": "sha512-UKW6PKtID0P9pUlbTy3SRbhWghHbyIjoYK/rbp1Tq2jVRmES9mLGcpO4azpP/JgsC7btjLYN7BvyDzVp6Ob7aw==", + "license": "MIT", "engines": { "node": ">=16.0.0" }, @@ -2828,9 +2410,10 @@ } }, "node_modules/@dicebear/croodles-neutral": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@dicebear/croodles-neutral/-/croodles-neutral-8.0.1.tgz", - "integrity": "sha512-DlR1wxzacRc3GhkMRg4MJ4CBfci/Z96SUl3YpvhHQ4ZtPldaQmdxs3jzOlnG1cuNRkqmiB1D66EXj5146V5WMA==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@dicebear/croodles-neutral/-/croodles-neutral-8.0.2.tgz", + "integrity": "sha512-2XvtlCe1/LPLRyrpgWkNroWzc8wB5ycz/nWdLOyTExD8ik4QQzKvUEbADxaTe1WsfTEr3fN/CN4EMk32UH5erg==", + "license": "MIT", "engines": { "node": ">=16.0.0" }, @@ -2839,9 +2422,10 @@ } }, "node_modules/@dicebear/fun-emoji": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@dicebear/fun-emoji/-/fun-emoji-8.0.1.tgz", - "integrity": "sha512-s2zXyZ7Rp3E2OHxAghhKIYmTtQ64D1VU+/p0VNaIQTPnyfxgpdrKlBMAlp4fXHyirhtAWCHSWgXcU9UFvlmr+w==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@dicebear/fun-emoji/-/fun-emoji-8.0.2.tgz", + "integrity": "sha512-F0GrSJTgfV5sKlXCuZ5fQFTkeAv10301rZjAN6nxdxEtaG3iM1NnGpVFnPYtyl/dyHNsTgRuzNz8g0qrDuMQLw==", + "license": "MIT", "engines": { "node": ">=16.0.0" }, @@ -2850,9 +2434,10 @@ } }, "node_modules/@dicebear/icons": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@dicebear/icons/-/icons-8.0.1.tgz", - "integrity": "sha512-uInO34VW1etgMsbarXIeYULTk+dlj0L9vW7nUinWqwwEbimgXT4iqzNSjQyogmQ3wmaahI1zNwrGUkfkQojouw==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@dicebear/icons/-/icons-8.0.2.tgz", + "integrity": "sha512-UAtAcsxSFxM6YtQFkMhu0/Xvk3tP/WA0OdZ0TZZdqCIldK5dzKFsiiixa3hwLQd9AB1SyJmHAL4XVrpkWF0ijQ==", + "license": "MIT", "engines": { "node": ">=16.0.0" }, @@ -2861,9 +2446,10 @@ } }, "node_modules/@dicebear/identicon": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@dicebear/identicon/-/identicon-8.0.1.tgz", - "integrity": "sha512-mIHBuUlTs1RNZg+9k4NIjYXYjZBh08ksK/7Pmb+5twsoIPuAPjZ+FbQsfc27Wga/IuJfgf9mYBq6Sxc8/LQxjg==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@dicebear/identicon/-/identicon-8.0.2.tgz", + "integrity": "sha512-4ZejuMquE5XnN41XxZ+Tpssfv4pbFQcCFyXvDPsQv6rLT9WSj/JEXUgVNRNQSHwDEh+UzR01l5JtzOrQhw1hDw==", + "license": "MIT", "engines": { "node": ">=16.0.0" }, @@ -2872,9 +2458,10 @@ } }, "node_modules/@dicebear/initials": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@dicebear/initials/-/initials-8.0.1.tgz", - "integrity": "sha512-ctO1f92XAms72qkhiKI/vvS/E6mco1RiTEACPJGv6hDPfdjR1vxpkzFpo3jm3RohfwOPCN5fH2l3BSinnlbzzw==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@dicebear/initials/-/initials-8.0.2.tgz", + "integrity": "sha512-wVknmFQiCdpNgM/a0Szh3LLOJU4zK5xyzIRHejJ2KyBx2WtDfiNZjgeDM9kjg/QGWk3t3cql4ZLlzqn2DHVcEA==", + "license": "MIT", "engines": { "node": ">=16.0.0" }, @@ -2883,9 +2470,10 @@ } }, "node_modules/@dicebear/lorelei": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@dicebear/lorelei/-/lorelei-8.0.1.tgz", - "integrity": "sha512-AY9XDeV7pIojDziiT/9flPWvH/5dswlVvezHQljmLa1H6EIQAIRWj9INeDaS2u2hRTFQKVeYQ1kuP3Omb+t26A==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@dicebear/lorelei/-/lorelei-8.0.2.tgz", + "integrity": "sha512-Gi/f+QWfWYZD90h9QNPkmFM6iNrp+vD8LMmapH8DQBIIV5gEaHB0AQ54y0kCqnWbv0597E6rwPkdDGO4fuEVJw==", + "license": "MIT", "engines": { "node": ">=16.0.0" }, @@ -2894,9 +2482,10 @@ } }, "node_modules/@dicebear/lorelei-neutral": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@dicebear/lorelei-neutral/-/lorelei-neutral-8.0.1.tgz", - "integrity": "sha512-vC5M7jg6UByJyFjBitLB3xKr435FdH8BHD8oVzf9A2MXi/ovQ0bEak9MnxVcrxUufJx7bsgS/XCRYNLUwaQKyw==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@dicebear/lorelei-neutral/-/lorelei-neutral-8.0.2.tgz", + "integrity": "sha512-cENa3xII5mnJ88Y61AHLTOJhhnxtFX4a/cSJ6XapwkjUVTKkNLDGWKinC6bw7A3AWFTUf2MmOg3kVlFtX6ExeQ==", + "license": "MIT", "engines": { "node": ">=16.0.0" }, @@ -2905,9 +2494,10 @@ } }, "node_modules/@dicebear/micah": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@dicebear/micah/-/micah-8.0.1.tgz", - "integrity": "sha512-B7+YCX62CqnjLlJNY6+NXy+HJlyGMzCbrnE38bGdmnH7PZ1IrEnmJny41AcopKziE02h65kdwCZFXy/v7piT4g==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@dicebear/micah/-/micah-8.0.2.tgz", + "integrity": "sha512-H7YYdZbvWGJGBsPgmrPQuxWp/OMUff/Y70tE+comR6bGjIJyGM9hoTNBviflaC2INK9c0ieUCmvo185axxHVfQ==", + "license": "MIT", "engines": { "node": ">=16.0.0" }, @@ -2916,9 +2506,10 @@ } }, "node_modules/@dicebear/miniavs": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@dicebear/miniavs/-/miniavs-8.0.1.tgz", - "integrity": "sha512-mzNAa2cIvsyeRuSnWoQ6l23yiw4BhmzrwdmfJZuDLloh/UNJjyiiCItYSTBmhtxcJrWX8YQTd/2hPdXjsdceTA==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@dicebear/miniavs/-/miniavs-8.0.2.tgz", + "integrity": "sha512-xjuZUS7tBeWjbzGlGmgLh6gbIQLQ8TJQyeP0+Pal0bQxzhufxT452v4vAw38Meuz94B5Mm6VR+9bQjr10fd8eQ==", + "license": "MIT", "engines": { "node": ">=16.0.0" }, @@ -2927,9 +2518,10 @@ } }, "node_modules/@dicebear/notionists": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@dicebear/notionists/-/notionists-8.0.1.tgz", - "integrity": "sha512-wOZPSj7lKIJkxiJHysGUVehPmaisWV9dUNhs4jDApiit3u6cbspDEOXvlAn/68cpGP8LfjsdyCp8yhZ9Wvk15Q==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@dicebear/notionists/-/notionists-8.0.2.tgz", + "integrity": "sha512-XLG85pKqW32M92zI0Aw8Hg1pE2+lAn9hs7zEwGsud2sCamQeE8jZWuWBZ89ktizWiZVzNMlHNUuMmxGoiHNlqg==", + "license": "MIT", "engines": { "node": ">=16.0.0" }, @@ -2938,9 +2530,10 @@ } }, "node_modules/@dicebear/notionists-neutral": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@dicebear/notionists-neutral/-/notionists-neutral-8.0.1.tgz", - "integrity": "sha512-j70iiLZPpLw9JfyziRC8jUaVnbz2NPTZFMd+O08ba3FcTsG0H5+bYimTWL+6fxZ/psN1S3NS/onVvgPkvBWTjg==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@dicebear/notionists-neutral/-/notionists-neutral-8.0.2.tgz", + "integrity": "sha512-p+gZXAujRupRy7k9rEmcZE7kcqx1qbO7GMfyqsPCenqS3lNEZ+vEh7Rlz/rOY4xks1W4t/dtd/my2nJRqjjcIA==", + "license": "MIT", "engines": { "node": ">=16.0.0" }, @@ -2949,9 +2542,10 @@ } }, "node_modules/@dicebear/open-peeps": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@dicebear/open-peeps/-/open-peeps-8.0.1.tgz", - "integrity": "sha512-NQbXmnPjyz3YZOAIEzQY6OFXg3sCIIDZgQZjl3qzTqsmUtZVMRnX8Sk53ig1SIM1kxIAyJ908wplwIYV16zxsw==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@dicebear/open-peeps/-/open-peeps-8.0.2.tgz", + "integrity": "sha512-fZb4C6mkZpp70tRWcogPS1PZGF0k3pclXswXhGKBdL1g0ULr157BCXBlx9juCOZ2K8w6teLQ5VE/uP490ddPUw==", + "license": "MIT", "engines": { "node": ">=16.0.0" }, @@ -2960,9 +2554,10 @@ } }, "node_modules/@dicebear/personas": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@dicebear/personas/-/personas-8.0.1.tgz", - "integrity": "sha512-qxivUbnx4xvE1PvqCg6pBQadVDJVjXaXnxtIUxIRJyDeYIJUxkeBr2A5JOIiNLdypqXoYwhURy5r3NCmesaAWg==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@dicebear/personas/-/personas-8.0.2.tgz", + "integrity": "sha512-8Xe4gaO/uJTwOMFBQv9AXJa0G8gzmqRtiH9UDrhs0yNF5Hh4g2yOeoefRBbLP/SuU5zSSHIZpcHKQD9Q1C30tA==", + "license": "MIT", "engines": { "node": ">=16.0.0" }, @@ -2971,9 +2566,10 @@ } }, "node_modules/@dicebear/pixel-art": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@dicebear/pixel-art/-/pixel-art-8.0.1.tgz", - "integrity": "sha512-WMRKdxP8/PL2UGiLAP7CdgTNaIRpFyLdr+u6RyXAUmWiI25ltnZQjctzCfUrO/Nxywc6L6lBkApZtTaP+X+UHg==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@dicebear/pixel-art/-/pixel-art-8.0.2.tgz", + "integrity": "sha512-wYGeMg7tAubilL0oIqYTFA6tMY6kQoWZe66Yi3UqYVa3/FvOfW6hagBG3zLhv6KIRA3/d4u3l78u+bR1UyeJ+A==", + "license": "MIT", "engines": { "node": ">=16.0.0" }, @@ -2982,9 +2578,10 @@ } }, "node_modules/@dicebear/pixel-art-neutral": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@dicebear/pixel-art-neutral/-/pixel-art-neutral-8.0.1.tgz", - "integrity": "sha512-jrbwMNjLk8hlOm+hMTT43z2DqXEFtv6/8hhms7VZE9FjcB1GrQy8j6tSClTq/ktkZlWofEGfvD8BrG5HsbKvaw==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@dicebear/pixel-art-neutral/-/pixel-art-neutral-8.0.2.tgz", + "integrity": "sha512-PdteTJB14YHK6nHWc6ZxnDEfzzskDB5dnddE77zx23PcF7mebssFGSF0cyXGAtfKh5AWgIYJfQU4urzKXCkbJQ==", + "license": "MIT", "engines": { "node": ">=16.0.0" }, @@ -2993,9 +2590,10 @@ } }, "node_modules/@dicebear/rings": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@dicebear/rings/-/rings-8.0.1.tgz", - "integrity": "sha512-RcSXPJDdDiyAscUhJMI6pgOgk4or0nzjKndur44U6I+6s0qS3c74zfT//whLUnDnSO2ZTaUGAjQ5gGJtzp5fqQ==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@dicebear/rings/-/rings-8.0.2.tgz", + "integrity": "sha512-aCyTiYo8nGzUjJ8PD0ctErcvbKe1UEaeWHvKcQERLDX8WLQMykBJquFodhNgN97TjZ8+8ur+vsrR+g8B9Z0zDw==", + "license": "MIT", "engines": { "node": ">=16.0.0" }, @@ -3004,9 +2602,10 @@ } }, "node_modules/@dicebear/shapes": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@dicebear/shapes/-/shapes-8.0.1.tgz", - "integrity": "sha512-Duhe3bcKmcYt7GcUsNP4/OIbcHzgb4L7rfuMpUgqjXKATLYq1Wizsw9/y9wrwII8h7wIMxG6RDSndNbd7ISTtA==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@dicebear/shapes/-/shapes-8.0.2.tgz", + "integrity": "sha512-5GaeUP8QkC7yuUutQCGiMH2U7ditdpKxfRjzlSG9uqaWV/RZZ0u190POawHIu7VpsuHWzMBRV9yu1l7Lc7wQFg==", + "license": "MIT", "engines": { "node": ">=16.0.0" }, @@ -3015,9 +2614,10 @@ } }, "node_modules/@dicebear/thumbs": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@dicebear/thumbs/-/thumbs-8.0.1.tgz", - "integrity": "sha512-cK3UeVVWtiGbStpYeKJrCw3Wy+LGNS5sFja2O3ogc/qpjiL7WFX7kYJXOE2neqOUxVItDxg7dfGatxFrsgUTYA==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@dicebear/thumbs/-/thumbs-8.0.2.tgz", + "integrity": "sha512-sHKuGbd3TW9eihMvjv2Wg/gqkNgPeXyWA/cmMKSFb0BRGK2AiGyrLnRswdx4YkWVsTLd+WH2GQC4o6HMGnAJ/Q==", + "license": "MIT", "engines": { "node": ">=16.0.0" }, @@ -3026,15 +2626,16 @@ } }, "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==", + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.12.0.tgz", + "integrity": "sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw==", + "license": "MIT", "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", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.2.0", "babel-plugin-macros": "^3.1.0", "convert-source-map": "^1.5.0", "escape-string-regexp": "^4.0.0", @@ -3044,47 +2645,49 @@ } }, "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", + "version": "11.13.1", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.13.1.tgz", + "integrity": "sha512-iqouYkuEblRcXmylXIwwOodiEK5Ifl7JcX7o6V4jI3iW4mLXX3dmt5xwBtIkJiQEXFAI+pC8X0i67yiPkH9Ucw==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.0", + "@emotion/weak-memoize": "^0.4.0", "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==" + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==", + "license": "MIT" }, "node_modules/@emotion/is-prop-valid": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz", - "integrity": "sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.3.0.tgz", + "integrity": "sha512-SHetuSLvJDzuNbOdtPVbq6yMMMlLoW5Q94uDqJZqy50gcmAjxFkVqmzqSGEFq9gT2iMuIeKV1PXVWmvUhuZLlQ==", "dependencies": { - "@emotion/memoize": "^0.8.1" + "@emotion/memoize": "^0.9.0" } }, "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==" + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==" }, "node_modules/@emotion/react": { - "version": "11.11.4", - "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.4.tgz", - "integrity": "sha512-t8AjMlF0gHpvvxk5mAtCqR4vmxiGHCeJBaQO6gncUSdklELOgtwjerNY2yuJNfwnc6vi16U/+uMF+afIawJ9iw==", + "version": "11.13.3", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.13.3.tgz", + "integrity": "sha512-lIsdU6JNrmYfJ5EbUCf4xW1ovy5wKQ2CkPRM4xogziOxH1nXxBSjpC9YqbFAP7circxMfYp+6x676BqWcEiixg==", "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", + "@emotion/babel-plugin": "^11.12.0", + "@emotion/cache": "^11.13.0", + "@emotion/serialize": "^1.3.1", + "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", + "@emotion/utils": "^1.4.0", + "@emotion/weak-memoize": "^0.4.0", "hoist-non-react-statics": "^3.3.1" }, "peerDependencies": { @@ -3097,33 +2700,34 @@ } }, "node_modules/@emotion/serialize": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.4.tgz", - "integrity": "sha512-RIN04MBT8g+FnDwgvIUi8czvr1LU1alUMI05LekWB5DGyTm8cCBMCRpq3GqaiyEDRptEXOyXnvZ58GZYu4kBxQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.1.tgz", + "integrity": "sha512-dEPNKzBPU+vFPGa+z3axPRn8XVDetYORmDC0wAiej+TNcOZE70ZMJa0X7JdeoM6q/nWTMZeLpN/fTnD9o8MQBA==", "dependencies": { - "@emotion/hash": "^0.9.1", - "@emotion/memoize": "^0.8.1", - "@emotion/unitless": "^0.8.1", - "@emotion/utils": "^1.2.1", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.10.0", + "@emotion/utils": "^1.4.0", "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==" + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==", + "license": "MIT" }, "node_modules/@emotion/styled": { - "version": "11.11.5", - "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.11.5.tgz", - "integrity": "sha512-/ZjjnaNKvuMPxcIiUkf/9SHoG4Q196DRl1w82hQ3WCsjo1IUR8uaGWrC6a87CrYAW0Kb/pK7hk8BnLgLRi9KoQ==", + "version": "11.13.0", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.13.0.tgz", + "integrity": "sha512-tkzkY7nQhW/zC4hztlwucpT8QEZ6eUzpXDRhww/Eej4tFfO0FxQYWRyg/c5CCXa4d/f174kqeXYjuQRnhzf6dA==", "dependencies": { "@babel/runtime": "^7.18.3", - "@emotion/babel-plugin": "^11.11.0", - "@emotion/is-prop-valid": "^1.2.2", - "@emotion/serialize": "^1.1.4", - "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", - "@emotion/utils": "^1.2.1" + "@emotion/babel-plugin": "^11.12.0", + "@emotion/is-prop-valid": "^1.3.0", + "@emotion/serialize": "^1.3.0", + "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", + "@emotion/utils": "^1.4.0" }, "peerDependencies": { "@emotion/react": "^11.0.0-rc.0", @@ -3136,422 +2740,78 @@ } }, "node_modules/@emotion/unitless": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", - "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==" + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==" }, "node_modules/@emotion/use-insertion-effect-with-fallbacks": { - "version": "1.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==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.1.0.tgz", + "integrity": "sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw==", + "license": "MIT", "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==" + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.0.tgz", + "integrity": "sha512-spEnrA1b6hDR/C68lC2M7m6ALPUHZC0lIY7jAS/B/9DuuO1ZP04eov8SMv/6fwRd8pzmsn2AuJEznRREWlQrlQ==", + "license": "MIT" }, "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==" + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", + "license": "MIT" }, - "node_modules/@esbuild/aix-ppc64": { + "node_modules/@esbuild/win32-x64": { "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", "cpu": [ - "ppc64" + "x64" ], - "dev": true, "optional": true, "os": [ - "aix" + "win32" ], "engines": { "node": ">=12" } }, - "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/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": [ - "android" - ], + "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-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-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" - ], + "license": "MIT", "engines": { - "node": ">=12" + "node": "^12.0.0 || ^14.0.0 || >=16.0.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/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "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/@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" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "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" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "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" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "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" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "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" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "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" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "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" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "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" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "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" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "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" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "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" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "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" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "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" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "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" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "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" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "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" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "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" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "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" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "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==", - "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.5.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", - "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.0.tgz", - "integrity": "sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A==", + "license": "MIT", + "peer": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -3574,6 +2834,9 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -3588,12 +2851,18 @@ "node_modules/@eslint/eslintrc/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==" + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0", + "peer": true }, "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "peer": true, "dependencies": { "type-fest": "^0.20.2" }, @@ -3608,6 +2877,9 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "peer": true, "dependencies": { "argparse": "^2.0.1" }, @@ -3618,12 +2890,18 @@ "node_modules/@eslint/eslintrc/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==" + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT", + "peer": true }, "node_modules/@eslint/eslintrc/node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "peer": true, "engines": { "node": ">=10" }, @@ -3632,9 +2910,12 @@ } }, "node_modules/@eslint/js": { - "version": "8.44.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.44.0.tgz", - "integrity": "sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true, + "license": "MIT", + "peer": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } @@ -3656,10 +2937,24 @@ "@floating-ui/utils": "^0.2.0" } }, + "node_modules/@floating-ui/react": { + "version": "0.26.25", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.25.tgz", + "integrity": "sha512-hZOmgN0NTOzOuZxI1oIrDu3Gcl8WViIkvPMpB4xdd4QD6xAMtwgwr3VPoiyH/bLtRcS1cDnhxLSD1NsMJmwh/A==", + "dependencies": { + "@floating-ui/react-dom": "^2.1.2", + "@floating-ui/utils": "^0.2.8", + "tabbable": "^6.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, "node_modules/@floating-ui/react-dom": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.9.tgz", - "integrity": "sha512-q0umO0+LQK4+p6aGyvzASqKbKOJcAHJ7ycE9CuUvfx3s9zTHWmGJTPOIlM/hmSBfUfg/XfY5YhLBLR/LHwShQQ==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.2.tgz", + "integrity": "sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==", "dependencies": { "@floating-ui/dom": "^1.0.0" }, @@ -3669,16 +2964,9 @@ } }, "node_modules/@floating-ui/utils": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.2.tgz", - "integrity": "sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw==" - }, - "node_modules/@gar/promisify": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", - "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", - "optional": true, - "peer": true + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.8.tgz", + "integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==" }, "node_modules/@graphql-typed-document-node/core": { "version": "3.2.0", @@ -3689,12 +2977,16 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", - "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "license": "Apache-2.0", + "peer": true, "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", "minimatch": "^3.0.5" }, "engines": { @@ -3705,6 +2997,8 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "peer": true, "engines": { "node": ">=12.22" }, @@ -3714,14 +3008,19 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true, + "license": "BSD-3-Clause", + "peer": true }, "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": { "camelcase": "^5.3.1", "find-up": "^4.1.0", @@ -3737,6 +3036,7 @@ "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" } @@ -3745,6 +3045,7 @@ "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, "engines": { "node": ">=8" } @@ -3759,6 +3060,7 @@ "version": "27.5.1", "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz", "integrity": "sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==", + "dev": true, "dependencies": { "@jest/types": "^27.5.1", "@types/node": "*", @@ -3775,6 +3077,7 @@ "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" @@ -3790,6 +3093,7 @@ "version": "27.5.1", "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.5.1.tgz", "integrity": "sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==", + "dev": true, "dependencies": { "@jest/console": "^27.5.1", "@jest/reporters": "^27.5.1", @@ -3836,6 +3140,7 @@ "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" @@ -3851,6 +3156,7 @@ "version": "27.5.1", "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", + "dev": true, "dependencies": { "@jest/fake-timers": "^27.5.1", "@jest/types": "^27.5.1", @@ -3865,6 +3171,7 @@ "version": "27.5.1", "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", + "dev": true, "dependencies": { "@jest/types": "^27.5.1", "@sinonjs/fake-timers": "^8.0.1", @@ -3881,6 +3188,7 @@ "version": "27.5.1", "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz", "integrity": "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==", + "dev": true, "dependencies": { "@jest/environment": "^27.5.1", "@jest/types": "^27.5.1", @@ -3894,6 +3202,7 @@ "version": "27.5.1", "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.5.1.tgz", "integrity": "sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==", + "dev": true, "dependencies": { "@bcoe/v8-coverage": "^0.2.3", "@jest/console": "^27.5.1", @@ -3937,6 +3246,7 @@ "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" @@ -3952,25 +3262,16 @@ "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/@jest/schemas": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", - "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", - "dependencies": { - "@sinclair/typebox": "^0.24.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, "node_modules/@jest/source-map": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz", "integrity": "sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==", + "dev": true, "dependencies": { "callsites": "^3.0.0", "graceful-fs": "^4.2.9", @@ -3984,6 +3285,7 @@ "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" } @@ -3992,6 +3294,7 @@ "version": "27.5.1", "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.5.1.tgz", "integrity": "sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==", + "dev": true, "dependencies": { "@jest/console": "^27.5.1", "@jest/types": "^27.5.1", @@ -4006,6 +3309,7 @@ "version": "27.5.1", "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz", "integrity": "sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==", + "dev": true, "dependencies": { "@jest/test-result": "^27.5.1", "graceful-fs": "^4.2.9", @@ -4020,6 +3324,7 @@ "version": "27.5.1", "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", + "dev": true, "dependencies": { "@babel/core": "^7.1.0", "@jest/types": "^27.5.1", @@ -4045,6 +3350,7 @@ "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" @@ -4060,6 +3366,7 @@ "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" } @@ -4068,6 +3375,7 @@ "version": "27.5.1", "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dev": true, "dependencies": { "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", @@ -4083,6 +3391,7 @@ "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" @@ -4095,13 +3404,13 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "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.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" @@ -4116,9 +3425,9 @@ } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "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" } @@ -4127,6 +3436,8 @@ "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "optional": true, + "peer": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.0", "@jridgewell/trace-mapping": "^0.3.9" @@ -4138,80 +3449,30 @@ "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "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" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" - }, - "node_modules/@kurkle/color": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz", - "integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==" - }, - "node_modules/@leichtgewicht/ip-codec": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", - "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" - }, "node_modules/@microsoft/tsdoc": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.2.tgz", - "integrity": "sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==", + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.15.0.tgz", + "integrity": "sha512-HZpPoABogPvjeJOdzCOSJsXeL/SMCBgBZMVC3X3d7YYp2gf31MfxhUoYUNwf1ERPJOnQc0wkFn9trqI6ZEdZuA==", "dev": true }, "node_modules/@microsoft/tsdoc-config": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.16.2.tgz", - "integrity": "sha512-OGiIzzoBLgWWR0UdRJX98oYO+XKGf7tiK4Zk6tQ/E4IJqGCe7dvkTvgDZV5cFJUzLGDOjeAXrnZoA6QkVySuxw==", + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.17.0.tgz", + "integrity": "sha512-v/EYRXnCAIHxOHW+Plb6OWuUoMotxTN0GLatnpOb1xq0KuTNw/WI3pamJx/UbsoJP5k9MCw1QxvvhPcF9pH3Zg==", "dev": true, "dependencies": { - "@microsoft/tsdoc": "0.14.2", - "ajv": "~6.12.6", + "@microsoft/tsdoc": "0.15.0", + "ajv": "~8.12.0", "jju": "~1.4.0", - "resolve": "~1.19.0" - } - }, - "node_modules/@microsoft/tsdoc-config/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/@microsoft/tsdoc-config/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/@microsoft/tsdoc-config/node_modules/resolve": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", - "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", - "dev": true, - "dependencies": { - "is-core-module": "^2.1.0", - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "resolve": "~1.22.2" } }, "node_modules/@mui/base": { @@ -4245,36 +3506,28 @@ } } }, - "node_modules/@mui/base/node_modules/clsx": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", - "engines": { - "node": ">=6" - } - }, "node_modules/@mui/core-downloads-tracker": { - "version": "5.15.20", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.15.20.tgz", - "integrity": "sha512-DoL2ppgldL16utL8nNyj/P12f8mCNdx/Hb/AJnX9rLY4b52hCMIx1kH83pbXQ6uMy6n54M3StmEbvSGoj2OFuA==", + "version": "5.16.7", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.16.7.tgz", + "integrity": "sha512-RtsCt4Geed2/v74sbihWzzRs+HsIQCfclHeORh5Ynu2fS4icIKozcSubwuG7vtzq2uW3fOR1zITSP84TNt2GoQ==", "funding": { "type": "opencollective", "url": "https://opencollective.com/mui-org" } }, "node_modules/@mui/icons-material": { - "version": "5.14.0", - "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.14.0.tgz", - "integrity": "sha512-z7lYNteDi1GMkF9JP/m2RWuCYK1M/FlaeBSUK7/IhIYzIXNhAVjfD8jRq5vFBV31qkEi2aGBS2z5SfLXwH6U0A==", + "version": "5.16.7", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.16.7.tgz", + "integrity": "sha512-UrGwDJCXEszbDI7yV047BYU5A28eGJ79keTCP4cc74WyncuVrnurlmIRxaHL8YK+LI1Kzq+/JM52IAkNnv4u+Q==", "dependencies": { - "@babel/runtime": "^7.22.5" + "@babel/runtime": "^7.23.9" }, "engines": { "node": ">=12.0.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" }, "peerDependencies": { "@mui/material": "^5.0.0", @@ -4288,21 +3541,21 @@ } }, "node_modules/@mui/material": { - "version": "5.15.20", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.15.20.tgz", - "integrity": "sha512-tVq3l4qoXx/NxUgIx/x3lZiPn/5xDbdTE8VrLczNpfblLYZzlrbxA7kb9mI8NoBF6+w9WE9IrxWnKK5KlPI2bg==", + "version": "5.16.7", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.16.7.tgz", + "integrity": "sha512-cwwVQxBhK60OIOqZOVLFt55t01zmarKJiJUWbk0+8s/Ix5IaUzAShqlJchxsIQ4mSrWqgcKCCXKtIlG5H+/Jmg==", "dependencies": { "@babel/runtime": "^7.23.9", - "@mui/base": "5.0.0-beta.40", - "@mui/core-downloads-tracker": "^5.15.20", - "@mui/system": "^5.15.20", - "@mui/types": "^7.2.14", - "@mui/utils": "^5.15.20", + "@mui/core-downloads-tracker": "^5.16.7", + "@mui/system": "^5.16.7", + "@mui/types": "^7.2.15", + "@mui/utils": "^5.16.6", + "@popperjs/core": "^2.11.8", "@types/react-transition-group": "^4.4.10", "clsx": "^2.1.0", "csstype": "^3.1.3", "prop-types": "^15.8.1", - "react-is": "^18.2.0", + "react-is": "^18.3.1", "react-transition-group": "^4.4.5" }, "engines": { @@ -4331,21 +3584,13 @@ } } }, - "node_modules/@mui/material/node_modules/clsx": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", - "engines": { - "node": ">=6" - } - }, "node_modules/@mui/private-theming": { - "version": "5.15.20", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.15.20.tgz", - "integrity": "sha512-BK8F94AIqSrnaPYXf2KAOjGZJgWfvqAVQ2gVR3EryvQFtuBnG6RwodxrCvd3B48VuMy6Wsk897+lQMUxJyk+6g==", + "version": "5.16.6", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.16.6.tgz", + "integrity": "sha512-rAk+Rh8Clg7Cd7shZhyt2HGTTE5wYKNSJ5sspf28Fqm/PZ69Er9o6KX25g03/FG2dfpg5GCwZh/xOojiTfm3hw==", "dependencies": { "@babel/runtime": "^7.23.9", - "@mui/utils": "^5.15.20", + "@mui/utils": "^5.16.6", "prop-types": "^15.8.1" }, "engines": { @@ -4366,9 +3611,9 @@ } }, "node_modules/@mui/styled-engine": { - "version": "5.15.14", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.15.14.tgz", - "integrity": "sha512-RILkuVD8gY6PvjZjqnWhz8fu68dVkqhM5+jYWfB5yhlSQKg+2rHkmEwm75XIeAqI3qwOndK6zELK5H6Zxn4NHw==", + "version": "5.16.6", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.16.6.tgz", + "integrity": "sha512-zaThmS67ZmtHSWToTiHslbI8jwrmITcN93LQaR2lKArbvS7Z3iLkwRoiikNWutx9MBs8Q6okKvbZq1RQYB3v7g==", "dependencies": { "@babel/runtime": "^7.23.9", "@emotion/cache": "^11.11.0", @@ -4397,15 +3642,15 @@ } }, "node_modules/@mui/system": { - "version": "5.15.20", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.15.20.tgz", - "integrity": "sha512-LoMq4IlAAhxzL2VNUDBTQxAb4chnBe8JvRINVNDiMtHE2PiPOoHlhOPutSxEbaL5mkECPVWSv6p8JEV+uykwIA==", + "version": "5.16.7", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.16.7.tgz", + "integrity": "sha512-Jncvs/r/d/itkxh7O7opOunTqbbSSzMTHzZkNLM+FjAOg+cYAZHrPDlYe1ZGKUYORwwb2XexlWnpZp0kZ4AHuA==", "dependencies": { "@babel/runtime": "^7.23.9", - "@mui/private-theming": "^5.15.20", - "@mui/styled-engine": "^5.15.14", - "@mui/types": "^7.2.14", - "@mui/utils": "^5.15.20", + "@mui/private-theming": "^5.16.4", + "@mui/styled-engine": "^5.16.4", + "@mui/types": "^7.2.15", + "@mui/utils": "^5.16.4", "clsx": "^2.1.0", "csstype": "^3.1.3", "prop-types": "^15.8.1" @@ -4435,18 +3680,10 @@ } } }, - "node_modules/@mui/system/node_modules/clsx": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", - "engines": { - "node": ">=6" - } - }, "node_modules/@mui/types": { - "version": "7.2.14", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.14.tgz", - "integrity": "sha512-MZsBZ4q4HfzBsywtXgM1Ksj6HDThtiwmOKUXH1pKYISI9gAVXCNHNpo7TlGoGrBaYWZTdNoirIN7JsQcQUjmQQ==", + "version": "7.2.15", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.15.tgz", + "integrity": "sha512-nbo7yPhtKJkdf9kcVOF8JZHPZTmqXjJ/tI0bdWgHg5tp9AnIN4Y7f7wm9T+0SyGYJk76+GYZ8Q5XaTYAsUHN0Q==", "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0" }, @@ -4457,14 +3694,16 @@ } }, "node_modules/@mui/utils": { - "version": "5.15.20", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.15.20.tgz", - "integrity": "sha512-mAbYx0sovrnpAu1zHc3MDIhPqL8RPVC5W5xcO1b7PiSCJPtckIZmBkp8hefamAvUiAV8gpfMOM6Zb+eSisbI2A==", + "version": "5.16.6", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.16.6.tgz", + "integrity": "sha512-tWiQqlhxAt3KENNiSRL+DIn9H5xNVK6Jjf70x3PnfQPz1MPBdh7yyIcAyVBT9xiw7hP3SomRhPR7hzBMBCjqEA==", "dependencies": { "@babel/runtime": "^7.23.9", - "@types/prop-types": "^15.7.11", + "@mui/types": "^7.2.15", + "@types/prop-types": "^15.7.12", + "clsx": "^2.1.1", "prop-types": "^15.8.1", - "react-is": "^18.2.0" + "react-is": "^18.3.1" }, "engines": { "node": ">=12.0.0" @@ -4484,22 +3723,17 @@ } }, "node_modules/@mui/x-charts": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@mui/x-charts/-/x-charts-7.6.2.tgz", - "integrity": "sha512-oG22NRno1+HSLV/9jVLThnHAKN4g+MXOO6GqaQxN9LM0hjt1tgRsrNAlfcJndmj/dVwqFtynkFB5qWnTEBZs7Q==", - "dependencies": { - "@babel/runtime": "^7.24.6", - "@mui/base": "^5.0.0-beta.40", - "@mui/system": "^5.15.15", - "@mui/utils": "^5.15.14", - "@react-spring/rafz": "^9.7.3", - "@react-spring/web": "^9.7.3", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@mui/x-charts/-/x-charts-7.17.0.tgz", + "integrity": "sha512-xDH/lOnb57+VBIA7q+1KlC0Ht1O46d/N2MEl1tUq1JYIXhA2Owi5cp+bcaof8Rvw5ApCmkoBxyUIjqT0guNIwA==", + "dependencies": { + "@babel/runtime": "^7.25.6", + "@mui/utils": "^5.16.6", + "@mui/x-charts-vendor": "7.16.0", + "@mui/x-internals": "7.17.0", + "@react-spring/rafz": "^9.7.4", + "@react-spring/web": "^9.7.4", "clsx": "^2.1.1", - "d3-color": "^3.1.0", - "d3-delaunay": "^6.0.4", - "d3-interpolate": "^3.0.1", - "d3-scale": "^4.0.2", - "d3-shape": "^3.2.0", "prop-types": "^15.8.1" }, "engines": { @@ -4508,7 +3742,8 @@ "peerDependencies": { "@emotion/react": "^11.9.0", "@emotion/styled": "^11.8.1", - "@mui/material": "^5.15.14", + "@mui/material": "^5.15.14 || ^6.0.0", + "@mui/system": "^5.15.14 || ^6.0.0", "react": "^17.0.0 || ^18.0.0", "react-dom": "^17.0.0 || ^18.0.0" }, @@ -4521,51 +3756,87 @@ } } }, - "node_modules/@mui/x-charts/node_modules/clsx": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "node_modules/@mui/x-charts-vendor": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@mui/x-charts-vendor/-/x-charts-vendor-7.16.0.tgz", + "integrity": "sha512-MyMCCl7eAM53rLbjqP4zbMy5hYtdeqCjAYCH2jpvBKdgugm2eaPLKOPM8bUVfen0wHA8BXleQrIrNceytFPyZA==", + "dependencies": { + "@babel/runtime": "^7.25.6", + "@types/d3-color": "^3.1.3", + "@types/d3-delaunay": "^6.0.4", + "@types/d3-interpolate": "^3.0.4", + "@types/d3-scale": "^4.0.8", + "@types/d3-shape": "^3.1.6", + "@types/d3-time": "^3.0.3", + "d3-color": "^3.1.0", + "d3-delaunay": "^6.0.4", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.2.0", + "d3-time": "^3.1.0", + "delaunator": "^5.0.1", + "robust-predicates": "^3.0.2" + } + }, + "node_modules/@mui/x-charts/node_modules/@mui/x-internals": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-7.17.0.tgz", + "integrity": "sha512-FLlAGSJl/vsuaA/8hPGazXFppyzIzxApJJDZMoTS0geUmHd0hyooISV2ltllLmrZ/DGtHhI08m8GGnHL6/vVeg==", + "dependencies": { + "@babel/runtime": "^7.25.6", + "@mui/utils": "^5.16.6" + }, "engines": { - "node": ">=6" + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0" } }, "node_modules/@mui/x-data-grid": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/@mui/x-data-grid/-/x-data-grid-6.20.0.tgz", - "integrity": "sha512-N9a4eJRmWgP5zT2AZ41BnBgCSQJiw4dc5Q2U9zQ5aOhOs+8Jb218tX79MIAfwt1s4rbTZmgAdsBUn9Xs93Kmrw==", + "version": "7.22.0", + "resolved": "https://registry.npmjs.org/@mui/x-data-grid/-/x-data-grid-7.22.0.tgz", + "integrity": "sha512-gXl7+hG0YRNU3YODlPvz6Q/9+EeUsPAWn/u2YMQmYTgwAxeY5QE3lY224VRnwM5v9SfTFheo1kzAKmXPdjb9tQ==", "dependencies": { - "@babel/runtime": "^7.23.2", - "@mui/utils": "^5.14.16", - "clsx": "^2.0.0", + "@babel/runtime": "^7.25.7", + "@mui/utils": "^5.16.6 || ^6.0.0", + "@mui/x-internals": "7.21.0", + "clsx": "^2.1.1", "prop-types": "^15.8.1", - "reselect": "^4.1.8" + "reselect": "^5.1.1" }, "engines": { "node": ">=14.0.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" }, "peerDependencies": { - "@mui/material": "^5.4.1", - "@mui/system": "^5.4.1", + "@emotion/react": "^11.9.0", + "@emotion/styled": "^11.8.1", + "@mui/material": "^5.15.14 || ^6.0.0", + "@mui/system": "^5.15.14 || ^6.0.0", "react": "^17.0.0 || ^18.0.0", "react-dom": "^17.0.0 || ^18.0.0" - } - }, - "node_modules/@mui/x-data-grid/node_modules/clsx": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", - "engines": { - "node": ">=6" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } } }, "node_modules/@mui/x-date-pickers": { - "version": "7.6.1", - "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-7.6.1.tgz", - "integrity": "sha512-erSq5cnOUyBgBmpHnMxIit5yhT3bl/lOaNZKpObvJtvEJetvNA9xWQ7dz/J/AufLzDuvThjusuRD0y+GmeXtiw==", + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-7.12.1.tgz", + "integrity": "sha512-Zj8kt3SCQbJp1qhMi+A3I4KqB8i5OY2Q11mdOEathFhqN/SQm1sUjIa1G09cGP1dPDgK1a6KM6qJGNtcw/nuWA==", "dependencies": { "@babel/runtime": "^7.24.6", "@mui/base": "^5.0.0-beta.40", @@ -4627,26 +3898,30 @@ } } }, - "node_modules/@mui/x-date-pickers/node_modules/clsx": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { - "version": "5.1.1-v1", - "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", - "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "node_modules/@mui/x-internals": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-7.21.0.tgz", + "integrity": "sha512-94YNyZ0BhK5Z+Tkr90RKf47IVCW8R/1MvdUhh6MCQg6sZa74jsX+x+gEZ4kzuCqOsuyTyxikeQ8vVuCIQiP7UQ==", "dependencies": { - "eslint-scope": "5.1.1" + "@babel/runtime": "^7.25.7", + "@mui/utils": "^5.16.6 || ^6.0.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0" } }, "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" @@ -4659,6 +3934,7 @@ "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" } @@ -4667,6 +3943,7 @@ "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" @@ -4679,6 +3956,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/@pdf-lib/standard-fonts/-/standard-fonts-1.0.0.tgz", "integrity": "sha512-hU30BK9IUN/su0Mn9VdlVKsWBS6GyhVfqjwl1FjZN4TxP6cCw0jP2w7V3Hf5uX7M0AZJ16vey9yE0ny7Sa59ZA==", + "license": "MIT", "dependencies": { "pako": "^1.0.6" } @@ -4687,6 +3965,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/@pdf-lib/upng/-/upng-1.0.1.tgz", "integrity": "sha512-dQK2FUMQtowVP00mtIksrlZhdFXQZPC+taih1q4CvPZ5vqdxR/LKBaFg0oAfzd1GlHZXXSPdQfzQnt+ViGvEIQ==", + "license": "MIT", "dependencies": { "pako": "^1.0.10" } @@ -4695,6 +3974,7 @@ "version": "1.2.6", "resolved": "https://registry.npmjs.org/@pdfme/common/-/common-1.2.6.tgz", "integrity": "sha512-ROmQ/iMUdmFS2QXD/kKDdcU5T6H3azDs2b1hE/OXs8531BPZ9ABbu9+1NRZQoNK4U/zP2F+Osb/B8ckr9lAmGg==", + "peer": true, "dependencies": { "buffer": "^6.0.3", "fontkit": "^2.0.2", @@ -4705,35 +3985,47 @@ } }, "node_modules/@pdfme/generator": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@pdfme/generator/-/generator-1.2.6.tgz", - "integrity": "sha512-rAkhr4vYa0OxVubAvLI/UIgD9+sCrcBG1SZpFCBVILgZjpqkUsscXdyukRtmHP6WaNAFGINch6PZVoshyQdGPw==", + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/@pdfme/generator/-/generator-4.5.2.tgz", + "integrity": "sha512-lwvNnknTjAlmThkdxNJLcr/1/gYUW1H6xvtdX7t1OSQ/oEJfgcR9oFsUsR+OTnEYDN4zXkAmQbm1K/tnjNQWVA==", "dependencies": { - "@pdfme/common": "latest", - "@pdfme/pdf-lib": "^1.17.3", + "@pdfme/pdf-lib": "^1.18.3", "atob": "^2.1.2", - "bwip-js": "^3.2.2", "fontkit": "^2.0.2" }, - "engines": { - "node": ">=14" + "peerDependencies": { + "@pdfme/common": "latest", + "@pdfme/schemas": "latest" } }, "node_modules/@pdfme/pdf-lib": { - "version": "1.17.3", - "resolved": "https://registry.npmjs.org/@pdfme/pdf-lib/-/pdf-lib-1.17.3.tgz", - "integrity": "sha512-k3cyms42I7jVycwDuzZuLD7A9J/D8Ud1iGJ7BpAfF54QYKxG0mUG6jTDJnc+tHrpNrsoJ4iFqERy5XvMQ6SUsA==", + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/@pdfme/pdf-lib/-/pdf-lib-1.18.3.tgz", + "integrity": "sha512-Zy4lRrxhDo7pbexNCvn+nzO5gLRc1XOXQyFOHC1FJoaHzrZ3GDd4OZwR5AaGIlCwV7ocPP2+iiLFA5wQcx3s9w==", + "license": "MIT", "dependencies": { "@pdf-lib/standard-fonts": "^1.0.0", "@pdf-lib/upng": "^1.0.1", - "pako": "^1.0.11", - "tslib": "^1.11.1" + "color": "^4.2.3", + "node-html-better-parser": "^1.4.0", + "pako": "^1.0.11" } }, - "node_modules/@pdfme/pdf-lib/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + "node_modules/@pdfme/schemas": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@pdfme/schemas/-/schemas-4.3.2.tgz", + "integrity": "sha512-hx6xjj9j1VLaPGf+UhA9aBIx8cSRtW3ev71AQwKpBd8QdvhuHpjPSIt5q1XGhGH8FLR8poBh1XsuyeK8yadgMg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@pdfme/pdf-lib": "^1.18.3", + "bwip-js": "^4.1.1", + "fast-xml-parser": "^4.3.2", + "fontkit": "^2.0.2" + }, + "peerDependencies": { + "@pdfme/common": "latest" + } }, "node_modules/@pkgr/core": { "version": "0.1.1", @@ -4747,187 +4039,63 @@ "url": "https://opencollective.com/unts" } }, - "node_modules/@pmmmwh/react-refresh-webpack-plugin": { - "version": "0.5.10", - "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.10.tgz", - "integrity": "sha512-j0Ya0hCFZPd4x40qLzbhGsh9TMtdb+CJQiso+WxLOPNasohq9cc5SNUcwsZaRH6++Xh91Xkm/xHCkuIiIu0LUA==", + "node_modules/@polka/url": { + "version": "1.0.0-next.21", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz", + "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==", + "dev": true + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@react-aria/ssr": { + "version": "3.9.5", + "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.5.tgz", + "integrity": "sha512-xEwGKoysu+oXulibNUSkXf8itW0npHHTa6c4AyYeZIJyRoegeteYuFpZUBPtIDE8RfHdNsSmE1ssOkxRnwbkuQ==", "dependencies": { - "ansi-html-community": "^0.0.8", - "common-path-prefix": "^3.0.0", - "core-js-pure": "^3.23.3", - "error-stack-parser": "^2.0.6", - "find-up": "^5.0.0", - "html-entities": "^2.1.0", - "loader-utils": "^2.0.4", - "schema-utils": "^3.0.0", - "source-map": "^0.7.3" + "@swc/helpers": "^0.5.0" }, "engines": { - "node": ">= 10.13" + "node": ">= 12" }, "peerDependencies": { - "@types/webpack": "4.x || 5.x", - "react-refresh": ">=0.10.0 <1.0.0", - "sockjs-client": "^1.4.0", - "type-fest": ">=0.17.0 <4.0.0", - "webpack": ">=4.43.0 <6.0.0", - "webpack-dev-server": "3.x || 4.x", - "webpack-hot-middleware": "2.x", - "webpack-plugin-serve": "0.x || 1.x" - }, - "peerDependenciesMeta": { - "@types/webpack": { - "optional": true - }, - "sockjs-client": { - "optional": true - }, - "type-fest": { - "optional": true - }, - "webpack-dev-server": { - "optional": true - }, - "webpack-hot-middleware": { - "optional": true - }, - "webpack-plugin-serve": { - "optional": true - } + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, - "node_modules/@pmmmwh/react-refresh-webpack-plugin/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==", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@pmmmwh/react-refresh-webpack-plugin/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==", - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" - } - }, - "node_modules/@pmmmwh/react-refresh-webpack-plugin/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==", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@pmmmwh/react-refresh-webpack-plugin/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==", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@pmmmwh/react-refresh-webpack-plugin/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==", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@polka/url": { - "version": "1.0.0-next.21", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz", - "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==", - "dev": true - }, - "node_modules/@popperjs/core": { - "version": "2.11.8", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", - "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/popperjs" - } - }, - "node_modules/@react-aria/ssr": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.7.0.tgz", - "integrity": "sha512-bfufjg4ESE5giN+Fxj1XIzS5f/YIhqcGc+Ve+vUUKU8xZ8t/Xtjlv8F3kjqDBQdk//n3mluFY7xG1wQVB9rMLQ==", - "dependencies": { - "@swc/helpers": "^0.5.0" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" - } - }, - "node_modules/@react-aria/ssr/node_modules/@swc/helpers": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.1.tgz", - "integrity": "sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==", + "node_modules/@react-aria/ssr/node_modules/@swc/helpers": { + "version": "0.5.12", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.12.tgz", + "integrity": "sha512-KMZNXiGibsW9kvZAO1Pam2JPTDBm+KSHMMHWdsyI/1DbIZjT2A6Gy3hblVXUMEDvUAKq+e0vL0X0o54owWji7g==", "dependencies": { "tslib": "^2.4.0" } }, "node_modules/@react-spring/animated": { - "version": "9.7.3", - "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.7.3.tgz", - "integrity": "sha512-5CWeNJt9pNgyvuSzQH+uy2pvTg8Y4/OisoscZIR8/ZNLIOI+CatFBhGZpDGTF/OzdNFsAoGk3wiUYTwoJ0YIvw==", + "version": "9.7.4", + "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.7.4.tgz", + "integrity": "sha512-7As+8Pty2QlemJ9O5ecsuPKjmO0NKvmVkRR1n6mEotFgWar8FKuQt2xgxz3RTgxcccghpx1YdS1FCdElQNexmQ==", "dependencies": { - "@react-spring/shared": "~9.7.3", - "@react-spring/types": "~9.7.3" + "@react-spring/shared": "~9.7.4", + "@react-spring/types": "~9.7.4" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, "node_modules/@react-spring/core": { - "version": "9.7.3", - "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.7.3.tgz", - "integrity": "sha512-IqFdPVf3ZOC1Cx7+M0cXf4odNLxDC+n7IN3MDcVCTIOSBfqEcBebSv+vlY5AhM0zw05PDbjKrNmBpzv/AqpjnQ==", + "version": "9.7.4", + "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.7.4.tgz", + "integrity": "sha512-GzjA44niEJBFUe9jN3zubRDDDP2E4tBlhNlSIkTChiNf9p4ZQlgXBg50qbXfSXHQPHak/ExYxwhipKVsQ/sUTw==", "dependencies": { - "@react-spring/animated": "~9.7.3", - "@react-spring/shared": "~9.7.3", - "@react-spring/types": "~9.7.3" + "@react-spring/animated": "~9.7.4", + "@react-spring/shared": "~9.7.4", + "@react-spring/types": "~9.7.4" }, "funding": { "type": "opencollective", @@ -4938,53 +4106,78 @@ } }, "node_modules/@react-spring/rafz": { - "version": "9.7.3", - "resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-9.7.3.tgz", - "integrity": "sha512-9vzW1zJPcC4nS3aCV+GgcsK/WLaB520Iyvm55ARHfM5AuyBqycjvh1wbmWmgCyJuX4VPoWigzemq1CaaeRSHhQ==" + "version": "9.7.4", + "resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-9.7.4.tgz", + "integrity": "sha512-mqDI6rW0Ca8IdryOMiXRhMtVGiEGLIO89vIOyFQXRIwwIMX30HLya24g9z4olDvFyeDW3+kibiKwtZnA4xhldA==" }, "node_modules/@react-spring/shared": { - "version": "9.7.3", - "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.7.3.tgz", - "integrity": "sha512-NEopD+9S5xYyQ0pGtioacLhL2luflh6HACSSDUZOwLHoxA5eku1UPuqcJqjwSD6luKjjLfiLOspxo43FUHKKSA==", + "version": "9.7.4", + "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.7.4.tgz", + "integrity": "sha512-bEPI7cQp94dOtCFSEYpxvLxj0+xQfB5r9Ru1h8OMycsIq7zFZon1G0sHrBLaLQIWeMCllc4tVDYRTLIRv70C8w==", "dependencies": { - "@react-spring/types": "~9.7.3" + "@react-spring/rafz": "~9.7.4", + "@react-spring/types": "~9.7.4" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, "node_modules/@react-spring/types": { - "version": "9.7.3", - "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.7.3.tgz", - "integrity": "sha512-Kpx/fQ/ZFX31OtlqVEFfgaD1ACzul4NksrvIgYfIFq9JpDHFwQkMVZ10tbo0FU/grje4rcL4EIrjekl3kYwgWw==" + "version": "9.7.4", + "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.7.4.tgz", + "integrity": "sha512-iQVztO09ZVfsletMiY+DpT/JRiBntdsdJ4uqk3UJFhrhS8mIC9ZOZbmfGSRs/kdbNPQkVyzucceDicQ/3Mlj9g==" }, "node_modules/@react-spring/web": { - "version": "9.7.3", - "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-9.7.3.tgz", - "integrity": "sha512-BXt6BpS9aJL/QdVqEIX9YoUy8CE6TJrU0mNCqSoxdXlIeNcEBWOfIyE6B14ENNsyQKS3wOWkiJfco0tCr/9tUg==", + "version": "9.7.4", + "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-9.7.4.tgz", + "integrity": "sha512-UMvCZp7I5HCVIleSa4BwbNxynqvj+mJjG2m20VO2yPoi2pnCYANy58flvz9v/YcXTAvsmL655FV3pm5fbr6akA==", "dependencies": { - "@react-spring/animated": "~9.7.3", - "@react-spring/core": "~9.7.3", - "@react-spring/shared": "~9.7.3", - "@react-spring/types": "~9.7.3" + "@react-spring/animated": "~9.7.4", + "@react-spring/core": "~9.7.4", + "@react-spring/shared": "~9.7.4", + "@react-spring/types": "~9.7.4" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/@reduxjs/toolkit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.3.0.tgz", + "integrity": "sha512-WC7Yd6cNGfHx8zf+iu+Q1UPTfEcXhQ+ATi7CV1hlrSAaQBdlPzg7Ww/wJHNQem7qG9rxmWoFCDCPubSvFObGzA==", + "dependencies": { + "immer": "^10.0.3", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", + "reselect": "^5.1.0" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18", + "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, "node_modules/@remix-run/router": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.16.1.tgz", - "integrity": "sha512-es2g3dq6Nb07iFxGk5GuHN20RwBZOsuDQN7izWIisUcv9r+d2C5jQxqmgkdebXgReWfiyUabcki6Fg77mSNrig==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.20.0.tgz", + "integrity": "sha512-mUnk8rPJBI9loFDZ+YzPGdeniYK+FTmRD1TMCz7ev2SNIozyKKpnGgsxO34u6Z4z/t0ITuu7voi/AshfsGsgFg==", + "license": "MIT", "engines": { "node": ">=14.0.0" } }, "node_modules/@restart/hooks": { - "version": "0.4.10", - "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.10.tgz", - "integrity": "sha512-HVZhYHb+9xnN6vDPyiTmw6N4V5wD9tatL3y0zpHFeeatP1ooOD1edzd3MnJCXYlb3OeleDg+Vv16EikGrH57eA==", + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.16.tgz", + "integrity": "sha512-f7aCv7c+nU/3mF7NWLtVVr0Ra80RqsO89hO72r+Y/nvQr5+q0UFGkocElTH6MJApvReVh6JHUFYn2cw1WdHF3w==", "dependencies": { "dequal": "^2.0.3" }, @@ -4993,9 +4186,9 @@ } }, "node_modules/@restart/ui": { - "version": "1.6.6", - "resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.6.6.tgz", - "integrity": "sha512-eC3puKuWE1SRYbojWHXnvCNHGgf3uzHCb6JOhnF4OXPibOIPEkR1sqDSkL643ydigxwh+ruCa1CmYHlzk7ikKA==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.8.0.tgz", + "integrity": "sha512-xJEOXUOTmT4FngTmhdjKFRrVVF0hwCLNPdatLCHkyS4dkiSK12cEu1Y0fjxktjJrdst9jJIc5J6ihMJCoWEN/g==", "dependencies": { "@babel/runtime": "^7.21.0", "@popperjs/core": "^2.11.6", @@ -5013,96 +4206,75 @@ } }, "node_modules/@restart/ui/node_modules/uncontrollable": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-8.0.2.tgz", - "integrity": "sha512-/GDx+K1STGtpgTsj5Dj3J51YaKxZDblbCQHTH1zHLuoBEWodj6MjtRVv3TUijj1JYLRLSFsFzN8NV4M3QV4d9w==", + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-8.0.4.tgz", + "integrity": "sha512-ulRWYWHvscPFc0QQXvyJjY6LIXU56f0h8pQFvhxiKk5V1fcI8gp9Ht9leVAhrVjzqMw0BgjspBINx9r6oyJUvQ==", "peerDependencies": { "react": ">=16.14.0" } }, - "node_modules/@rollup/plugin-babel": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", - "integrity": "sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==", + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.21.3.tgz", + "integrity": "sha512-fOvu7PCQjAj4eWDEuD8Xz5gpzFqXzGlxHZozHP4b9Jxv9APtdxL6STqztDzMLuRXEc4UpXGGhx029Xgm91QBeA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "dev": true + }, + "node_modules/@shikijs/core": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.17.6.tgz", + "integrity": "sha512-9ztslig6/YmCg/XwESAXbKjAjOhaq6HVced9NY6qcbDz1X5g/S90Wco2vMjBNX/6V71ASkzri76JewSGPa7kiQ==", "dependencies": { - "@babel/helper-module-imports": "^7.10.4", - "@rollup/pluginutils": "^3.1.0" - }, - "engines": { - "node": ">= 10.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0", - "@types/babel__core": "^7.1.9", - "rollup": "^1.20.0||^2.0.0" - }, - "peerDependenciesMeta": { - "@types/babel__core": { - "optional": true - } + "@shikijs/engine-javascript": "1.17.6", + "@shikijs/engine-oniguruma": "1.17.6", + "@shikijs/types": "1.17.6", + "@shikijs/vscode-textmate": "^9.2.2", + "@types/hast": "^3.0.4", + "hast-util-to-html": "^9.0.2" } }, - "node_modules/@rollup/plugin-node-resolve": { - "version": "11.2.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz", - "integrity": "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==", + "node_modules/@shikijs/engine-javascript": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-1.17.6.tgz", + "integrity": "sha512-5EEZj8tVcierNxm4V0UMS2PVoflb0UJPalWWV8l9rRg+oOfnr5VivqBJbkyq5grltVPvByIXvVbY8GSM/356jQ==", "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "@types/resolve": "1.17.1", - "builtin-modules": "^3.1.0", - "deepmerge": "^4.2.2", - "is-module": "^1.0.0", - "resolve": "^1.19.0" - }, - "engines": { - "node": ">= 10.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" + "@shikijs/types": "1.17.6", + "oniguruma-to-js": "0.4.3" } }, - "node_modules/@rollup/plugin-replace": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz", - "integrity": "sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==", + "node_modules/@shikijs/engine-oniguruma": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-1.17.6.tgz", + "integrity": "sha512-NLfWDMXFYe0nDHFbEoyZdz89aIIey3bTfF3zLYSUNTXks5s4uinZVmuPOFf1HfTeGqIn8uErJSBc3VnpJO7Alw==", "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "magic-string": "^0.25.7" - }, - "peerDependencies": { - "rollup": "^1.20.0 || ^2.0.0" + "@shikijs/types": "1.17.6", + "@shikijs/vscode-textmate": "^9.2.2" } }, - "node_modules/@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "node_modules/@shikijs/types": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-1.17.6.tgz", + "integrity": "sha512-ndTFa2TJi2w51ddKQDn3Jy8f6K4E5Q2x3dA3Hmsd3+YmxDQ10UWHjcw7VbVbKzv3VcUvYPLy+z9neqytSzUMUg==", "dependencies": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" - }, - "engines": { - "node": ">= 8.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" + "@shikijs/vscode-textmate": "^9.2.2", + "@types/hast": "^3.0.4" } }, - "node_modules/@rollup/pluginutils/node_modules/@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==" - }, - "node_modules/@rushstack/eslint-patch": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.3.2.tgz", - "integrity": "sha512-V+MvGwaHH03hYhY+k6Ef/xKd6RYlc4q8WBx+2ANmipHJcKuktNcI/NgEsJgdSUF6Lw32njT6OnrRsKYCdgHjYw==" - }, - "node_modules/@sinclair/typebox": { - "version": "0.24.51", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==" + "node_modules/@shikijs/vscode-textmate": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-9.2.2.tgz", + "integrity": "sha512-TMp15K+GGYrWlZM8+Lnj9EaHEFmOen0WJBrfa17hF7taDOYthuPPV0GWzfd/9iMij0akS/8Yw2ikquH7uVi/fg==" }, "node_modules/@sindresorhus/is": { "version": "0.14.0", @@ -5117,6 +4289,7 @@ "version": "1.8.6", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "dev": true, "dependencies": { "type-detect": "4.0.8" } @@ -5125,21 +4298,11 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", + "dev": true, "dependencies": { "@sinonjs/commons": "^1.7.0" } }, - "node_modules/@surma/rollup-plugin-off-main-thread": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", - "integrity": "sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==", - "dependencies": { - "ejs": "^3.1.6", - "json5": "^2.2.0", - "magic-string": "^0.25.0", - "string.prototype.matchall": "^4.0.6" - } - }, "node_modules/@svgr/babel-plugin-add-jsx-attribute": { "version": "6.5.1", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-6.5.1.tgz", @@ -5365,342 +4528,150 @@ "@svgr/core": "^6.0.0" } }, - "node_modules/@svgr/plugin-svgo": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-5.5.0.tgz", - "integrity": "sha512-r5swKk46GuQl4RrVejVwpeeJaydoxkdwkM1mBKOgJLBUJPGaLci6ylg/IjhrRsREKDkr4kbMWdgOtbXEh0fyLQ==", + "node_modules/@swc/helpers": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.14.tgz", + "integrity": "sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==", "dependencies": { - "cosmiconfig": "^7.0.0", - "deepmerge": "^4.2.2", - "svgo": "^1.2.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" + "tslib": "^2.4.0" } }, - "node_modules/@svgr/webpack": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-5.5.0.tgz", - "integrity": "sha512-DOBOK255wfQxguUta2INKkzPj6AIS6iafZYiYmHn6W3pHlycSRRlvWKCfLDG10fXfLWqE3DJHgRUOyJYmARa7g==", + "node_modules/@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dev": true, "dependencies": { - "@babel/core": "^7.12.3", - "@babel/plugin-transform-react-constant-elements": "^7.12.1", - "@babel/preset-env": "^7.12.1", - "@babel/preset-react": "^7.12.5", - "@svgr/core": "^5.5.0", - "@svgr/plugin-jsx": "^5.5.0", - "@svgr/plugin-svgo": "^5.5.0", - "loader-utils": "^2.0.0" + "defer-to-connect": "^1.0.1" }, "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" + "node": ">=6" } }, - "node_modules/@svgr/webpack/node_modules/@svgr/babel-plugin-add-jsx-attribute": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-5.4.0.tgz", - "integrity": "sha512-ZFf2gs/8/6B8PnSofI0inYXr2SDNTDScPXhN7k5EqD4aZ3gi6u+rbmZHVB8IM3wDyx8ntKACZbtXSm7oZGRqVg==", - "engines": { - "node": ">=10" + "node_modules/@testing-library/dom": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", + "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", + "dev": true, + "peer": 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" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - } - }, - "node_modules/@svgr/webpack/node_modules/@svgr/babel-plugin-remove-jsx-attribute": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-5.4.0.tgz", - "integrity": "sha512-yaS4o2PgUtwLFGTKbsiAy6D0o3ugcUhWK0Z45umJ66EPWunAz9fuFw2gJuje6wqQvQWOTJvIahUwndOXb7QCPg==", "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" + "node": ">=18" } }, - "node_modules/@svgr/webpack/node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-5.0.1.tgz", - "integrity": "sha512-LA72+88A11ND/yFIMzyuLRSMJ+tRKeYKeQ+mR3DcAZ5I4h5CPWN9AHyUzJbWSYp/u2u0xhmgOe0+E41+GjEueA==", - "engines": { - "node": ">=10" + "node_modules/@testing-library/dom/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, + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - } - }, - "node_modules/@svgr/webpack/node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-5.0.1.tgz", - "integrity": "sha512-PoiE6ZD2Eiy5mK+fjHqwGOS+IXX0wq/YDtNyIgOrc6ejFnxN4b13pRpiIPbtPwHEc+NT2KCjteAcq33/F1Y9KQ==", "engines": { "node": ">=10" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@svgr/webpack/node_modules/@svgr/babel-plugin-svg-dynamic-title": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-5.4.0.tgz", - "integrity": "sha512-zSOZH8PdZOpuG1ZVx/cLVePB2ibo3WPpqo7gFIjLV9a0QsuQAzJiwwqmuEdTaW2pegyBE17Uu15mOgOcgabQZg==", - "engines": { - "node": ">=10" + "node_modules/@testing-library/dom/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, + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - } - }, - "node_modules/@svgr/webpack/node_modules/@svgr/babel-plugin-svg-em-dimensions": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-5.4.0.tgz", - "integrity": "sha512-cPzDbDA5oT/sPXDCUYoVXEmm3VIoAWAPT6mSPTJNbQaBNUuEKVKyGH93oDY4e42PYHRW67N5alJx/eEol20abw==", "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/@svgr/webpack/node_modules/@svgr/babel-plugin-transform-react-native-svg": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-5.4.0.tgz", - "integrity": "sha512-3eYP/SaopZ41GHwXma7Rmxcv9uRslRDTY1estspeB1w1ueZWd/tPlMfEOoccYpEMZU3jD4OU7YitnXcF5hLW2Q==", + "node_modules/@testing-library/dom/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, + "peer": true, "engines": { "node": ">=10" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@svgr/webpack/node_modules/@svgr/babel-plugin-transform-svg-component": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-5.5.0.tgz", - "integrity": "sha512-q4jSH1UUvbrsOtlo/tKcgSeiCHRSBdXoIoqX1pgcKK/aU3JD27wmMKwGtpB8qRYUYoyXvfGxUVKchLuR5pB3rQ==", - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - } - }, - "node_modules/@svgr/webpack/node_modules/@svgr/babel-preset": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-5.5.0.tgz", - "integrity": "sha512-4FiXBjvQ+z2j7yASeGPEi8VD/5rrGQk4Xrq3EdJmoZgz/tpqChpo5hgXDvmEauwtvOc52q8ghhZK4Oy7qph4ig==", - "dependencies": { - "@svgr/babel-plugin-add-jsx-attribute": "^5.4.0", - "@svgr/babel-plugin-remove-jsx-attribute": "^5.4.0", - "@svgr/babel-plugin-remove-jsx-empty-expression": "^5.0.1", - "@svgr/babel-plugin-replace-jsx-attribute-value": "^5.0.1", - "@svgr/babel-plugin-svg-dynamic-title": "^5.4.0", - "@svgr/babel-plugin-svg-em-dimensions": "^5.4.0", - "@svgr/babel-plugin-transform-react-native-svg": "^5.4.0", - "@svgr/babel-plugin-transform-svg-component": "^5.5.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - } - }, - "node_modules/@svgr/webpack/node_modules/@svgr/core": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/core/-/core-5.5.0.tgz", - "integrity": "sha512-q52VOcsJPvV3jO1wkPtzTuKlvX7Y3xIcWRpCMtBF3MrteZJtBfQw/+u0B1BHy5ColpQc1/YVTrPEtSYIMNZlrQ==", - "dependencies": { - "@svgr/plugin-jsx": "^5.5.0", - "camelcase": "^6.2.0", - "cosmiconfig": "^7.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - } - }, - "node_modules/@svgr/webpack/node_modules/@svgr/hast-util-to-babel-ast": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-5.5.0.tgz", - "integrity": "sha512-cAaR/CAiZRB8GP32N+1jocovUtvlj0+e65TB50/6Lcime+EA49m/8l+P2ko+XPJ4dw3xaPS3jOL4F2X4KWxoeQ==", - "dependencies": { - "@babel/types": "^7.12.6" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - } - }, - "node_modules/@svgr/webpack/node_modules/@svgr/plugin-jsx": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-5.5.0.tgz", - "integrity": "sha512-V/wVh33j12hGh05IDg8GpIUXbjAPnTdPTKuP4VNLggnwaHMPNQNae2pRnyTAILWCQdz5GyMqtO488g7CKM8CBA==", - "dependencies": { - "@babel/core": "^7.12.3", - "@svgr/babel-preset": "^5.5.0", - "@svgr/hast-util-to-babel-ast": "^5.5.0", - "svg-parser": "^2.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - } - }, - "node_modules/@svgr/webpack/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/@svgr/webpack/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==", - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" - } - }, - "node_modules/@swc/helpers": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.14.tgz", - "integrity": "sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==", - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", - "dev": true, - "dependencies": { - "defer-to-connect": "^1.0.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@testing-library/dom": { - "version": "7.31.2", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.31.2.tgz", - "integrity": "sha512-3UqjCpey6HiTZT92vODYLPxTBWlM8ZOOjr3LX5F37/VRipW2M1kX6I/Cm4VXzteZqfGfagg8yXywpcOgQBlNsQ==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^4.2.0", - "aria-query": "^4.2.2", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.6", - "lz-string": "^1.4.4", - "pretty-format": "^26.6.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@testing-library/dom/node_modules/aria-query": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", - "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.10.2", - "@babel/runtime-corejs3": "^7.10.2" - }, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/@testing-library/dom/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@testing-library/dom/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, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } + "peer": true }, "node_modules/@testing-library/jest-dom": { - "version": "5.16.5", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.16.5.tgz", - "integrity": "sha512-N5ixQ2qKpi5OLYfwQmUb/5mSV9LneAcaUfp32pn4yCnpb8r/Yz0pXFPck21dIicKmi+ta5WRAknkZCfA8refMA==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.5.0.tgz", + "integrity": "sha512-xGGHpBXYSHUUr6XsKBfs85TWlYKpTc37cSBBVrXcib2MkHLboWlkClhWF37JKlDb9KEq3dHs+f2xR7XJEWGBxA==", "dev": true, "dependencies": { - "@adobe/css-tools": "^4.0.1", - "@babel/runtime": "^7.9.2", - "@types/testing-library__jest-dom": "^5.9.1", + "@adobe/css-tools": "^4.4.0", "aria-query": "^5.0.0", "chalk": "^3.0.0", "css.escape": "^1.5.1", - "dom-accessibility-api": "^0.5.6", - "lodash": "^4.17.15", + "dom-accessibility-api": "^0.6.3", + "lodash": "^4.17.21", "redent": "^3.0.0" }, "engines": { - "node": ">=8", + "node": ">=14", "npm": ">=6", "yarn": ">=1" } }, + "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, + "license": "MIT" + }, "node_modules/@testing-library/react": { - "version": "11.2.7", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-11.2.7.tgz", - "integrity": "sha512-tzRNp7pzd5QmbtXNG/mhdcl7Awfu/Iz1RaVHY75zTdOkmHCuzMhRL83gWHSgOAcjS3CCbyfwUHMZgRJb4kAfpA==", + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.0.1.tgz", + "integrity": "sha512-dSmwJVtJXmku+iocRhWOUFbrERC76TX2Mnf0ATODz8brzAZrMBbzLwQixlBSanZxR6LddK3eiwpSFZgDET1URg==", "dev": true, "dependencies": { - "@babel/runtime": "^7.12.5", - "@testing-library/dom": "^7.28.1" + "@babel/runtime": "^7.12.5" }, "engines": { - "node": ">=10" + "node": ">=18" }, "peerDependencies": { - "react": "*", - "react-dom": "*" + "@testing-library/dom": "^10.0.0", + "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0", + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, "node_modules/@testing-library/user-event": { @@ -5723,28 +4694,22 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true, "engines": { "node": ">= 6" } }, - "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": "4.2.2", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", - "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==", - "dev": true + "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, + "peer": true }, "node_modules/@types/babel__core": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.1.tgz", - "integrity": "sha512-aACu/U/omhdk15O4Nfb+fHgH/z3QsfQzpnvRZhYhThms83ZnAOZz7zZAWO7mn2yyNQaA4xTO8GLK3uqFU4bYYw==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", @@ -5778,93 +4743,84 @@ "@babel/types": "^7.20.7" } }, - "node_modules/@types/body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==" + }, + "node_modules/@types/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==" }, - "node_modules/@types/bonjour": { - "version": "3.5.10", - "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz", - "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==", + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", "dependencies": { - "@types/node": "*" + "@types/d3-color": "*" } }, - "node_modules/@types/connect": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", - "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "node_modules/@types/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-P2dlU/q51fkOc/Gfl3Ul9kicV7l+ra934qBFXCFhrZMOL6du1TM0pm1ThYvENukyOn5h9v+yMJ9Fn5JK4QozrQ==" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.8.tgz", + "integrity": "sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==", "dependencies": { - "@types/node": "*" + "@types/d3-time": "*" } }, - "node_modules/@types/connect-history-api-fallback": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz", - "integrity": "sha512-4x5FkPpLipqwthjPsF7ZRbOv3uoLUFkTA9G9v583qi4pACvq0uTELrB8OLUzPWUI4IJIyvM85vzkV1nyiI2Lig==", + "node_modules/@types/d3-shape": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.6.tgz", + "integrity": "sha512-5KKk5aKGu2I+O6SONMYSNflgiP0WfZIQvVUMan50wHsLG1G94JlxEVnCpQARfTtzytuY0p/9PXXZb3I7giofIA==", "dependencies": { - "@types/express-serve-static-core": "*", - "@types/node": "*" + "@types/d3-path": "*" } }, + "node_modules/@types/d3-time": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.3.tgz", + "integrity": "sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw==" + }, "node_modules/@types/eslint": { "version": "8.44.0", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.0.tgz", "integrity": "sha512-gsF+c/0XOguWgaOgvFs+xnnRqt9GwgTvIks36WpE6ueeI4KCEHHd8K/CKHqhOqrJKsYH8m27kRzQEvWXAwXUTw==", + "dev": true, + "optional": true, + "peer": true, "dependencies": { "@types/estree": "*", "@types/json-schema": "*" } }, - "node_modules/@types/eslint-scope": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", - "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, "node_modules/@types/estree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", - "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==" - }, - "node_modules/@types/express": { - "version": "4.17.17", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", - "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", - "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.17.35", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.35.tgz", - "integrity": "sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg==", - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" - } + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" }, "node_modules/@types/graceful-fs": { "version": "4.1.6", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", + "dev": true, "dependencies": { "@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==", + "dependencies": { + "@types/unist": "*" + } + }, "node_modules/@types/history": { "version": "4.7.11", "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", @@ -5872,32 +4828,14 @@ "dev": true }, "node_modules/@types/hoist-non-react-statics": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", - "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz", + "integrity": "sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==", "dependencies": { "@types/react": "*", "hoist-non-react-statics": "^3.3.0" } }, - "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==" - }, - "node_modules/@types/http-errors": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-/K3ds8TRAfBvi5vfjuz8y6+GiAYBZ0x4tXv1Av6CWBWn0IlADc+ZX9pMq7oU0fNQPnBwIZl3rmeLp6SBApbxSQ==" - }, - "node_modules/@types/http-proxy": { - "version": "1.17.11", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.11.tgz", - "integrity": "sha512-HC8G7c1WmaF2ekqpnFq626xd3Zz0uvaqFmBJNRZCGEZCXkvSdJoNFn/8Ygbd9fKNQj8UzLdCETaI0UWPAjK7IA==", - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/inquirer": { "version": "9.0.7", "resolved": "https://registry.npmjs.org/@types/inquirer/-/inquirer-9.0.7.tgz", @@ -5911,12 +4849,14 @@ "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==" + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true }, "node_modules/@types/istanbul-lib-report": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, "dependencies": { "@types/istanbul-lib-coverage": "*" } @@ -5925,6 +4865,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, "dependencies": { "@types/istanbul-lib-report": "*" } @@ -5953,26 +4894,24 @@ "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==" - }, - "node_modules/@types/mime": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", - "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true }, - "node_modules/@types/minimist": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", - "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", - "optional": true, - "peer": true + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "dependencies": { + "@types/unist": "*" + } }, "node_modules/@types/node": { - "version": "20.12.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz", - "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==", + "version": "22.5.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.4.tgz", + "integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==", + "devOptional": true, "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.19.2" } }, "node_modules/@types/node-fetch": { @@ -5999,13 +4938,6 @@ "node": ">= 6" } }, - "node_modules/@types/normalize-package-data": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", - "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", - "optional": true, - "peer": true - }, "node_modules/@types/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", @@ -6014,38 +4946,32 @@ "node_modules/@types/prettier": { "version": "2.7.3", "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", - "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==" + "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==", + "dev": true }, "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==" }, - "node_modules/@types/q": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.5.tgz", - "integrity": "sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ==" - }, - "node_modules/@types/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" - }, - "node_modules/@types/range-parser": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", - "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" - }, "node_modules/@types/react": { - "version": "17.0.62", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.62.tgz", - "integrity": "sha512-eANCyz9DG8p/Vdhr0ZKST8JV12PhH2ACCDYlFw6DIO+D+ca+uP4jtEDEpVqXZrh/uZdXQGwk7whJa3ah5DtyLw==", + "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==", "dependencies": { "@types/prop-types": "*", - "@types/scheduler": "*", "csstype": "^3.0.2" } }, + "node_modules/@types/react-beautiful-dnd": { + "version": "13.1.8", + "resolved": "https://registry.npmjs.org/@types/react-beautiful-dnd/-/react-beautiful-dnd-13.1.8.tgz", + "integrity": "sha512-E3TyFsro9pQuK4r8S/OL6G99eq7p8v29sX0PM7oT8Z+PJfZvSQTx4zTQbUJ+QZXioAF0e7TGBEcA1XhYhCweyQ==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/react-bootstrap": { "version": "0.32.32", "resolved": "https://registry.npmjs.org/@types/react-bootstrap/-/react-bootstrap-0.32.32.tgz", @@ -6056,81 +4982,30 @@ } }, "node_modules/@types/react-datepicker": { - "version": "4.11.2", - "resolved": "https://registry.npmjs.org/@types/react-datepicker/-/react-datepicker-4.11.2.tgz", - "integrity": "sha512-ELYyX3lb3K1WltqdlF1hbnaDGgzlF6PIR5T4W38cSEcfrQDIrPE+Ioq5pwRe/KEJ+ihHMjvTVZQkwJx0pWMNHQ==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@types/react-datepicker/-/react-datepicker-7.0.0.tgz", + "integrity": "sha512-4tWwOUq589tozyQPBVEqGNng5DaZkomx5IVNuur868yYdgjH6RaL373/HKiVt1IDoNNXYiTGspm1F7kjrarM8Q==", + "deprecated": "This is a stub types definition. react-datepicker provides its own type definitions, so you do not need this installed.", "dev": true, "dependencies": { - "@popperjs/core": "^2.9.2", - "@types/react": "*", - "date-fns": "^2.0.1", - "react-popper": "^2.2.5" + "react-datepicker": "*" } }, "node_modules/@types/react-dom": { - "version": "17.0.20", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.20.tgz", - "integrity": "sha512-4pzIjSxDueZZ90F52mU3aPoogkHIoSIDG+oQ+wQK7Cy2B9S+MvOqY0uEA/qawKz381qrEDkvpwyt8Bm31I8sbA==", - "dev": true, - "dependencies": { - "@types/react": "^17" - } - }, - "node_modules/@types/react-google-recaptcha": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@types/react-google-recaptcha/-/react-google-recaptcha-2.1.5.tgz", - "integrity": "sha512-iWTjmVttlNgp0teyh7eBXqNOQzVq2RWNiFROWjraOptRnb1OcHJehQnji0sjqIRAk9K0z8stjyhU+OLpPb0N6w==", + "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/react-redux": { - "version": "7.1.25", - "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.25.tgz", - "integrity": "sha512-bAGh4e+w5D8dajd6InASVIyCo4pZLJ66oLb80F9OBLO1gKESbZcRCJpTT6uLXX+HAB57zw1WTdwJdAsewuTweg==", + "node_modules/@types/resolve": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", + "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", "dependencies": { - "@types/hoist-non-react-statics": "^3.3.0", - "@types/react": "*", - "hoist-non-react-statics": "^3.3.0", - "redux": "^4.0.0" - } - }, - "node_modules/@types/react-router": { - "version": "5.1.20", - "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", - "integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==", - "dev": true, - "dependencies": { - "@types/history": "^4.7.11", - "@types/react": "*" - } - }, - "node_modules/@types/react-router-dom": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", - "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", - "dev": true, - "dependencies": { - "@types/history": "^4.7.11", - "@types/react": "*", - "@types/react-router": "*" - } - }, - "node_modules/@types/react-transition-group": { - "version": "4.4.10", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz", - "integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==", - "dependencies": { - "@types/react": "*" - } - }, - "node_modules/@types/resolve": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", - "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", - "dependencies": { - "@types/node": "*" + "@types/node": "*" } }, "node_modules/@types/retry": { @@ -10469,1395 +9344,1345 @@ "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-7.0.1.tgz", "integrity": "sha512-K6rNzvkIeHaTd8m/QEh1Zko0KI7BACWkkneSs6s9cKZC/J27X3eZR6Upt1jkmZ/4FK+XUOPPxMEN7+lbUXfSlA==", "dependencies": { - "@babel/core": "^7.16.0", - "@babel/eslint-parser": "^7.16.3", - "@rushstack/eslint-patch": "^1.1.0", - "@typescript-eslint/eslint-plugin": "^5.5.0", - "@typescript-eslint/parser": "^5.5.0", - "babel-preset-react-app": "^10.0.1", - "confusing-browser-globals": "^1.0.11", - "eslint-plugin-flowtype": "^8.0.3", - "eslint-plugin-import": "^2.25.3", - "eslint-plugin-jest": "^25.3.0", - "eslint-plugin-jsx-a11y": "^6.5.1", - "eslint-plugin-react": "^7.27.1", - "eslint-plugin-react-hooks": "^4.3.0", - "eslint-plugin-testing-library": "^5.0.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "eslint": "^8.0.0" + "@types/react": "*" } }, - "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==", + "node_modules/@types/react-redux": { + "version": "7.1.34", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.34.tgz", + "integrity": "sha512-GdFaVjEbYv4Fthm2ZLvj1VSCedV7TqE5y1kNwnjSdBOTXuRSgowux6J8TAct15T3CKBr63UMk+2CO7ilRhyrAQ==", "dependencies": { - "debug": "^3.2.7", - "is-core-module": "^2.13.0", - "resolve": "^1.22.4" + "@types/hoist-non-react-statics": "^3.3.0", + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0", + "redux": "^4.0.0" } }, - "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==", + "node_modules/@types/react-redux/node_modules/redux": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", "dependencies": { - "ms": "^2.1.1" + "@babel/runtime": "^7.9.2" } }, - "node_modules/eslint-module-utils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", - "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "node_modules/@types/react-router": { + "version": "5.1.20", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", + "integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==", + "dev": true, "dependencies": { - "debug": "^3.2.7" - }, - "engines": { - "node": ">=4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } + "@types/history": "^4.7.11", + "@types/react": "*" } }, - "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==", + "node_modules/@types/react-router-dom": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", + "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", + "dev": true, "dependencies": { - "ms": "^2.1.1" + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "*" } }, - "node_modules/eslint-plugin-flowtype": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-8.0.3.tgz", - "integrity": "sha512-dX8l6qUL6O+fYPtpNRideCFSpmWOUVx5QcaGLVqe/vlDiBSe4vYljDWDETwnyFzpl7By/WVIu6rcrniCgH9BqQ==", + "node_modules/@types/react-transition-group": { + "version": "4.4.10", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz", + "integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==", "dependencies": { - "lodash": "^4.17.21", - "string-natural-compare": "^3.0.1" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "@babel/plugin-syntax-flow": "^7.14.5", - "@babel/plugin-transform-react-jsx": "^7.14.9", - "eslint": "^8.1.0" + "@types/react": "*" } }, - "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==", + "node_modules/@types/sanitize-html": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/@types/sanitize-html/-/sanitize-html-2.13.0.tgz", + "integrity": "sha512-X31WxbvW9TjIhZZNyNBZ/p5ax4ti7qsNDBDEnH4zAgmEh35YnFD1UiS6z9Cd34kKm0LslFW0KPmTQzu/oGtsqQ==", + "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" + "htmlparser2": "^8.0.0" } }, - "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==", + "node_modules/@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "node_modules/@types/through": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/through/-/through-0.0.33.tgz", + "integrity": "sha512-HsJ+z3QuETzP3cswwtzt2vEIiHBk/dCcHGhbmG5X3ecnwFD/lPrMpliGXxSCg03L9AhrdwA4Oz/qfspkDW+xGQ==", + "dev": true, "dependencies": { - "ms": "^2.1.1" + "@types/node": "*" } }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "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==" + }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", + "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" + }, + "node_modules/@types/warning": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.3.tgz", + "integrity": "sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q==" + }, + "node_modules/@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "dev": true, "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" + "@types/yargs-parser": "*" } }, - "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==", - "bin": { - "semver": "bin/semver.js" - } + "node_modules/@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true }, - "node_modules/eslint-plugin-jest": { - "version": "25.7.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-25.7.0.tgz", - "integrity": "sha512-PWLUEXeeF7C9QGKqvdSbzLOiLTx+bno7/HC9eefePfEb257QFHg7ye3dh80AZVkaa/RQsBB1Q/ORQvg2X7F0NQ==", + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.11.0.tgz", + "integrity": "sha512-KhGn2LjW1PJT2A/GfDpiyOfS4a8xHQv2myUagTM5+zsormOmBlYsnQ6pobJ8XxJmh6hnHwa2Mbe3fPrDJoDhbA==", + "dev": true, "dependencies": { - "@typescript-eslint/experimental-utils": "^5.0.0" + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.11.0", + "@typescript-eslint/type-utils": "8.11.0", + "@typescript-eslint/utils": "8.11.0", + "@typescript-eslint/visitor-keys": "8.11.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^4.0.0 || ^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0" }, "peerDependenciesMeta": { - "@typescript-eslint/eslint-plugin": { - "optional": true - }, - "jest": { + "typescript": { "optional": true } } }, - "node_modules/eslint-plugin-jsx-a11y": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.1.tgz", - "integrity": "sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==", - "dependencies": { - "@babel/runtime": "^7.20.7", - "aria-query": "^5.1.3", - "array-includes": "^3.1.6", - "array.prototype.flatmap": "^1.3.1", - "ast-types-flow": "^0.0.7", - "axe-core": "^4.6.2", - "axobject-query": "^3.1.1", - "damerau-levenshtein": "^1.0.8", - "emoji-regex": "^9.2.2", - "has": "^1.0.3", - "jsx-ast-utils": "^3.3.3", - "language-tags": "=1.0.5", - "minimatch": "^3.1.2", - "object.entries": "^1.1.6", - "object.fromentries": "^2.0.6", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=4.0" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" - } - }, - "node_modules/eslint-plugin-jsx-a11y/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/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==", + "node_modules/@typescript-eslint/parser": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.5.0.tgz", + "integrity": "sha512-gF77eNv0Xz2UJg/NbpWJ0kqAm35UMsvZf1GHj8D9MRFTj/V3tAciIWXfmPLsAAF/vUlpWPvUDyH1jjsr0cMVWw==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.8.6" + "@typescript-eslint/scope-manager": "8.5.0", + "@typescript-eslint/types": "8.5.0", + "@typescript-eslint/typescript-estree": "8.5.0", + "@typescript-eslint/visitor-keys": "8.5.0", + "debug": "^4.3.4" }, "engines": { - "node": "^14.18.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint-plugin-prettier" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@types/eslint": ">=8.0.0", - "eslint": ">=8.0.0", - "eslint-config-prettier": "*", - "prettier": ">=3.0.0" + "eslint": "^8.57.0 || ^9.0.0" }, "peerDependenciesMeta": { - "@types/eslint": { - "optional": true - }, - "eslint-config-prettier": { + "typescript": { "optional": true } } }, - "node_modules/eslint-plugin-react": { - "version": "7.34.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.1.tgz", - "integrity": "sha512-N97CxlouPT1AHt8Jn0mhhN2RrADlUAsk1/atcT2KyA/l9Q/E6ll7OIGwNumFmWfZ9skV3XXccYS19h80rHtgkw==", + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.5.0.tgz", + "integrity": "sha512-06JOQ9Qgj33yvBEx6tpC8ecP9o860rsR22hWMEd12WcTRrfaFgHr2RB/CA/B+7BMhHkXT4chg2MyboGdFGawYg==", + "dev": true, + "license": "MIT", "dependencies": { - "array-includes": "^3.1.7", - "array.prototype.findlast": "^1.2.4", - "array.prototype.flatmap": "^1.3.2", - "array.prototype.toreversed": "^1.1.2", - "array.prototype.tosorted": "^1.1.3", - "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.0.17", - "estraverse": "^5.3.0", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.7", - "object.fromentries": "^2.0.7", - "object.hasown": "^1.1.3", - "object.values": "^1.1.7", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.5", - "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.10" + "@typescript-eslint/types": "8.5.0", + "@typescript-eslint/visitor-keys": "8.5.0" }, "engines": { - "node": ">=4" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/eslint-plugin-react-hooks": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", - "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.5.0.tgz", + "integrity": "sha512-qjkormnQS5wF9pjSi6q60bKUHH44j2APxfh9TQRXK8wbYVeDYYdYJGIROL87LGZZ2gz3Rbmjc736qyL8deVtdw==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=10" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/eslint-plugin-react/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.5.0.tgz", + "integrity": "sha512-vEG2Sf9P8BPQ+d0pxdfndw3xIXaoSjliG0/Ejk7UggByZPKXmJmw3GW5jV2gHNQNawBUyfahoSiCFVov0Ruf7Q==", + "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "esutils": "^2.0.2" + "@typescript-eslint/types": "8.5.0", + "@typescript-eslint/visitor-keys": "8.5.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": ">=0.10.0" - } - }, - "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==", - "engines": { - "node": ">=4.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "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==", + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.5.0.tgz", + "integrity": "sha512-yTPqMnbAZJNy2Xq2XU8AdtOW9tJIr+UQb64aXB9f3B1498Zx9JorVgFJcZpEc9UBuCCrdzKID2RGAMkYcDtZOw==", + "dev": true, + "license": "MIT", "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" + "@typescript-eslint/types": "8.5.0", + "eslint-visitor-keys": "^3.4.3" }, - "bin": { - "resolve": "bin/resolve" + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "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==", - "bin": { - "semver": "bin/semver.js" + "node_modules/@typescript-eslint/parser/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, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" } }, - "node_modules/eslint-plugin-testing-library": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.11.0.tgz", - "integrity": "sha512-ELY7Gefo+61OfXKlQeXNIDVVLPcvKTeiQOoMZG9TeuWa7Ln4dUNRv8JdRWBQI9Mbb427XGlVB1aa1QPZxBJM8Q==", + "node_modules/@typescript-eslint/parser/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, + "license": "ISC", "dependencies": { - "@typescript-eslint/utils": "^5.58.0" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0", - "npm": ">=6" + "node": ">=16 || 14 >=14.17" }, - "peerDependencies": { - "eslint": "^7.5.0 || ^8.0.0" + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/eslint-plugin-tsdoc": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/eslint-plugin-tsdoc/-/eslint-plugin-tsdoc-0.2.17.tgz", - "integrity": "sha512-xRmVi7Zx44lOBuYqG8vzTXuL6IdGOeF9nHX17bjJ8+VE6fsxpdGem0/SBTmAwgYMKYB1WBkqRJVQ+n8GK041pA==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.11.0.tgz", + "integrity": "sha512-Uholz7tWhXmA4r6epo+vaeV7yjdKy5QFCERMjs1kMVsLRKIrSdM6o21W2He9ftp5PP6aWOVpD5zvrvuHZC0bMQ==", "dev": true, "dependencies": { - "@microsoft/tsdoc": "0.14.2", - "@microsoft/tsdoc-config": "0.16.2" + "@typescript-eslint/types": "8.11.0", + "@typescript-eslint/visitor-keys": "8.11.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "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==", + "node_modules/@typescript-eslint/type-utils": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.11.0.tgz", + "integrity": "sha512-ItiMfJS6pQU0NIKAaybBKkuVzo6IdnAhPFZA/2Mba/uBjuPQPet/8+zh5GtLHwmuFRShZx+8lhIs7/QeDHflOg==", + "dev": true, "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "@typescript-eslint/typescript-estree": "8.11.0", + "@typescript-eslint/utils": "8.11.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": ">=8.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", - "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", + "node_modules/@typescript-eslint/types": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.11.0.tgz", + "integrity": "sha512-tn6sNMHf6EBAYMvmPUaKaVeYvhUsrE6x+bXQTxjQRp360h1giATU0WvgeEys1spbvb5R+VpNOZ+XJmjD8wOUHw==", + "dev": true, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/eslint-webpack-plugin": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-3.2.0.tgz", - "integrity": "sha512-avrKcGncpPbPSUHX6B3stNGzkKFto3eL+DKM4+VyMrVnhPc3vRczVlCq3uhuFOdRvDHTVXuzwk1ZKUrqDQHQ9w==", + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.11.0.tgz", + "integrity": "sha512-yHC3s1z1RCHoCz5t06gf7jH24rr3vns08XXhfEqzYpd6Hll3z/3g23JRi0jM8A47UFKNc3u/y5KIMx8Ynbjohg==", + "dev": true, "dependencies": { - "@types/eslint": "^7.29.0 || ^8.4.1", - "jest-worker": "^28.0.2", - "micromatch": "^4.0.5", - "normalize-path": "^3.0.0", - "schema-utils": "^4.0.0" + "@typescript-eslint/types": "8.11.0", + "@typescript-eslint/visitor-keys": "8.11.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": ">= 12.13.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0", - "webpack": "^5.0.0" - } - }, - "node_modules/eslint-webpack-plugin/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==", - "dependencies": { - "fast-deep-equal": "^3.1.3" + "url": "https://opencollective.com/typescript-eslint" }, - "peerDependencies": { - "ajv": "^8.8.2" + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/eslint-webpack-plugin/node_modules/jest-worker": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", - "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "node_modules/@typescript-eslint/typescript-estree/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": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "balanced-match": "^1.0.0" } }, - "node_modules/eslint-webpack-plugin/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==", + "node_modules/@typescript-eslint/typescript-estree/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": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">= 12.13.0" + "node": ">=16 || 14 >=14.17" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/eslint-webpack-plugin/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==", + "node_modules/@typescript-eslint/utils": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.11.0.tgz", + "integrity": "sha512-CYiX6WZcbXNJV7UNB4PLDIBtSdRmRI/nb0FMyqHPTQD1rMjA0foPLaPUV39C/MxkTd/QKSeX+Gb34PPsDVC35g==", + "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.11.0", + "@typescript-eslint/types": "8.11.0", + "@typescript-eslint/typescript-estree": "8.11.0" }, "engines": { - "node": ">=10" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/eslint/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "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" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" } }, - "node_modules/eslint/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/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.11.0.tgz", + "integrity": "sha512-EaewX6lxSjRJnc+99+dqzTeoDZUfyrA52d2/HRrkI830kgovWsmIiTfmr0NZorzqic7ga+1bS60lRBUgR3n/Bw==", + "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@typescript-eslint/types": "8.11.0", + "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": ">=10" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.1.tgz", - "integrity": "sha512-CvefSOsDdaYYvxChovdrPo/ZGt8d5lrJWleAc1diXRKhHGiTYEI26cvo8Kle/wGnsizoCJjK73FMg1/IkIwiNA==", + "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==", + "license": "ISC" + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.2.tgz", + "integrity": "sha512-hieu+o05v4glEBucTcKMK3dlES0OeJlD9YVOAPraVMOInBCwzumaIFiUjr4bHK7NPgnAHgiskUoceKercrN8vg==", "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "@babel/core": "^7.25.2", + "@babel/plugin-transform-react-jsx-self": "^7.24.7", + "@babel/plugin-transform-react-jsx-source": "^7.24.7", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.14.2" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^14.18.0 || >=16.0.0" }, - "funding": { - "url": "https://opencollective.com/eslint" + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0" } }, - "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==", + "node_modules/@vitejs/plugin-react/node_modules/react-refresh": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", + "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", "engines": { - "node": ">=4.0" + "node": ">=0.10.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==", + "node_modules/@wry/caches": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@wry/caches/-/caches-1.0.1.tgz", + "integrity": "sha512-bXuaUNLVVkD20wcGBWRyo7j9N3TxePEWFZj2Y+r9OoUzfqmavM84+mFykRicNsBqatba5JLay1t48wxaXaWnlA==", "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "tslib": "^2.3.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, - "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==", + "node_modules/@wry/context": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@wry/context/-/context-0.7.4.tgz", + "integrity": "sha512-jmT7Sb4ZQWI5iyu3lobQxICu2nC/vbUhP0vIdd6tHC9PTfenmRmuIFqktc6GH9cgi+ZHnsLWPvfSvc4DrYmKiQ==", "dependencies": { - "is-glob": "^4.0.3" + "tslib": "^2.3.0" }, "engines": { - "node": ">=10.13.0" + "node": ">=8" } }, - "node_modules/eslint/node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "node_modules/@wry/equality": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@wry/equality/-/equality-0.5.7.tgz", + "integrity": "sha512-BRFORjsTuQv5gxcXsuDXx6oGRhuVsEGwZy6LOzRRfgu+eSfxbhUQ9L9YtSEIuIjY/o7g3iWFjrc5eSY1GXP2Dw==", "dependencies": { - "type-fest": "^0.20.2" + "tslib": "^2.3.0" }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/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==", + "node_modules/@wry/trie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@wry/trie/-/trie-0.5.0.tgz", + "integrity": "sha512-FNoYzHawTMk/6KMQoEG5O4PuioX19UbwdQKF44yw0nLfOypfQdjtfZzo/UIJWAJ23sNIFbD1Ug9lbaDGMwbqQA==", "dependencies": { - "argparse": "^2.0.1" + "tslib": "^2.3.0" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": ">=8" } }, - "node_modules/eslint/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==" + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "dev": true }, - "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==", - "dependencies": { - "p-locate": "^5.0.0" + "node_modules/acorn": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "devOptional": true, + "bin": { + "acorn": "bin/acorn" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.4.0" } }, - "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==", + "node_modules/acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "dev": true, "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" } }, - "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==", - "dependencies": { - "p-limit": "^3.0.2" + "node_modules/acorn-globals/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": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.4.0" } }, - "node_modules/eslint/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "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, + "license": "MIT", + "peer": 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": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.4.0" } }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "debug": "4" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">= 6.0.0" } }, - "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==", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" + "node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" }, - "engines": { - "node": ">=4" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dev": true, "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" + "string-width": "^4.1.0" } }, - "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==", + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dependencies": { + "type-fest": "^0.21.3" + }, "engines": { - "node": ">=4.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "node_modules/ansi-red": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-red/-/ansi-red-0.1.1.tgz", + "integrity": "sha512-ewaIr5y+9CUTGFwZfpECUbFlGcC0GCw1oqR9RI6h1gQCd9Aj2GxSckCnPsVJnmfMZbwFYE+leZGASgkWl06Jow==", "dependencies": { - "estraverse": "^5.2.0" + "ansi-wrap": "0.1.0" }, "engines": { - "node": ">=4.0" + "node": ">=0.10.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==", + "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==", "engines": { - "node": ">=4.0" + "node": ">=8" } }, - "node_modules/estraverse": { + "node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": ">=4.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==" - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "node_modules/ansi-wrap": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", + "integrity": "sha512-ZyznvL8k/FZeQHr2T6LzcJ/+vBApDnMNZvfVFy3At0knswWd6rJ3/0Hhmpu8oqa6C92npmozs890sX9Dl6q+Qw==", "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==", + "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==", + "devOptional": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, "engines": { - "node": ">= 0.6" + "node": ">= 8" } }, - "node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dependencies": { + "sprintf-js": "~1.0.2" + } }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "engines": { - "node": ">=0.8.x" + "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/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "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": { - "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" + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "engines": { - "node": ">= 0.8.0" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/expand-range": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", - "integrity": "sha512-AFASGfIlnIbkKPQwX1yHaDjFvh/1gyKJODme52V6IORh69uEYgZp0o9C+qsIGNVEiuuhQU0CSSl++Rlegg1qvA==", + "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": { - "fill-range": "^2.1.0" + "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.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/expand-range/node_modules/fill-range": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", - "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", + "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": { - "is-number": "^2.1.0", - "isobject": "^2.0.0", - "randomatic": "^3.0.0", - "repeat-element": "^1.1.2", - "repeat-string": "^1.5.2" + "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.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/expand-range/node_modules/is-number": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", - "integrity": "sha512-QUzH43Gfb9+5yckcrSA0VBDwEtDUchrk4F6tfJZQuNzDJbEDB9cZNzSfXGQ1jqmdDY/kl41lUOWM9syA8z8jlg==", + "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": { - "kind-of": "^3.0.2" + "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.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/expand-range/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "node_modules/expand-range/node_modules/isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", + "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": { - "isarray": "1.0.0" + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/expand-range/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "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": { - "is-buffer": "^1.1.5" + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", + "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": { - "homedir-polyfill": "^1.0.1" + "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.10.0" + "node": ">= 0.4" } }, - "node_modules/expect": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", - "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "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": { - "@jest/types": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1" + "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": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.1", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.5.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" + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "bin": { + "atob": "bin/atob.js" }, "engines": { - "node": ">= 0.10.0" + "node": ">= 4.5.0" } }, - "node_modules/express/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==" - }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/autolinker": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/autolinker/-/autolinker-0.28.1.tgz", + "integrity": "sha512-zQAFO1Dlsn69eXaO6+7YZc+v84aquQKbwpzCE3L0stj56ERn9hutFxPopViLjo9G+rWwjozRhgS5KJ25Xy19cQ==", "dependencies": { - "ms": "2.0.0" + "gulp-header": "^1.7.1" } }, - "node_modules/express/node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "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": { - "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" + "possible-typed-array-names": "^1.0.0" }, "engines": { - "node": ">= 0.8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/express/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==", + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "dev": true, "dependencies": { - "ee-first": "1.1.1" + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" }, "engines": { - "node": ">= 0.8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" } }, - "node_modules/express/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==" - }, - "node_modules/express/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "node_modules/babel-jest/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": ">= 0.8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "optional": true, - "peer": true - }, - "node_modules/external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "node_modules/babel-jest/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": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" + "@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": ">=4" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/external-editor/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==", + "node_modules/babel-jest/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": { - "safer-buffer": ">= 2.1.2 < 3" + "@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": ">=0.10.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", - "engines": [ - "node >=0.6.0" - ], - "optional": true, - "peer": true + "node_modules/babel-jest/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/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==" - }, - "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/babel-jest/node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } }, - "node_modules/fast-glob": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.0.tgz", - "integrity": "sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==", + "node_modules/babel-jest/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": { - "@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" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=8.6.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "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==" - }, - "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==" + "node_modules/babel-jest/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/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "node_modules/babel-jest/node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dev": true, "dependencies": { - "reusify": "^1.0.4" + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" } }, - "node_modules/faye-websocket": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "node_modules/babel-jest/node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-jest/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, "dependencies": { - "websocket-driver": ">=0.5.1" + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" }, "engines": { - "node": ">=0.8.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/fb-watchman": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "node_modules/babel-jest/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": { - "bser": "2.1.1" + "@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/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "node_modules/babel-jest/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": { - "escape-string-regexp": "^1.0.5" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/figures/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==", + "node_modules/babel-jest/node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, "engines": { - "node": ">=0.8.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, "dependencies": { - "flat-cache": "^3.0.4" + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=8" } }, - "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==", + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "dev": true, "dependencies": { - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0" + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" }, "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/file-loader/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==", + "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": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" }, "engines": { - "node": ">=8.9.0" + "node": ">=10", + "npm": ">=6" } }, - "node_modules/filelist": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", - "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "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==", + "dev": true, "dependencies": { - "minimatch": "^5.0.1" + "@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/filelist/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==", - "dependencies": { - "balanced-match": "^1.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==", + "dev": true, + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/filelist/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "node_modules/babel-plugin-polyfill-corejs3": { + "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": { - "brace-expansion": "^2.0.1" + "@babel/helper-define-polyfill-provider": "^0.6.2", + "core-js-compat": "^3.38.0" }, - "engines": { - "node": ">=10" - } - }, - "node_modules/filesize": { - "version": "8.0.7", - "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", - "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==", - "engines": { - "node": ">= 0.4.0" + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.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==", + "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==", + "dev": true, "dependencies": { - "to-regex-range": "^5.0.1" + "@babel/helper-define-polyfill-provider": "^0.6.2" }, - "engines": { - "node": ">=8" + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "dev": true, + "node_modules/babel-plugin-transform-import-meta": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-import-meta/-/babel-plugin-transform-import-meta-2.2.1.tgz", + "integrity": "sha512-AxNh27Pcg8Kt112RGa3Vod2QS2YXKKJ6+nSvRtv7qQTJAdx0MZa4UHZ4lnxHUWA2MNbLuZQv5FVab4P1CoLOWw==", "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" + "@babel/template": "^7.4.4", + "tslib": "^2.4.0" }, - "engines": { - "node": ">= 0.8" + "peerDependencies": { + "@babel/core": "^7.10.0" } }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", "dev": true, "dependencies": { - "ms": "2.0.0" + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@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-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/finalhandler/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/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==", + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "dev": true, "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, - "funding": { - "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/find-node-modules": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/find-node-modules/-/find-node-modules-2.1.3.tgz", - "integrity": "sha512-UC2I2+nx1ZuOBclWVNdcnbDR5dlrOdVb7xNjmT/lHE+LsgztWks3dG7boJ37yTS/venXw84B/mAW9uHVoC5QRg==", - "dev": true, - "dependencies": { - "findup-sync": "^4.0.0", - "merge": "^2.1.1" - } + "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==" }, - "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/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "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/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "devOptional": true, "engines": { "node": ">=8" } }, - "node_modules/findup-sync": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", - "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==", - "dev": true, - "dependencies": { - "detect-file": "^1.0.0", - "is-glob": "^4.0.0", - "micromatch": "^4.0.2", - "resolve-dir": "^1.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/flag-icons": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/flag-icons/-/flag-icons-6.7.0.tgz", - "integrity": "sha512-+KXrrrXN2jiETFxisFl+3f83Bq7tj5nuIWnbv9fX59k05lvldEXRCOffybb5hAIjMWt4nmG0E8OfKt7Flm99Eg==" - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" } }, - "node_modules/flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==" - }, - "node_modules/follow-redirects": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", - "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", + "node_modules/bl/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "funding": [ { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" } ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/fontkit": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fontkit/-/fontkit-2.0.2.tgz", - "integrity": "sha512-jc4k5Yr8iov8QfS6u8w2CnHWVmbOGtdBtOXMze5Y+QD966Rx6PEVWXSEGwXlsDlKtu1G12cJjcsybnqhSk/+LA==", - "dependencies": { - "@swc/helpers": "^0.4.2", - "brotli": "^1.3.2", - "clone": "^2.1.2", - "dfa": "^1.2.0", - "fast-deep-equal": "^3.1.3", - "restructure": "^3.0.0", - "tiny-inflate": "^1.0.3", - "unicode-properties": "^1.4.0", - "unicode-trie": "^2.0.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==", "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", - "engines": { - "node": ">=0.10.0" + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" } }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", - "optional": true, - "peer": true, - "engines": { - "node": "*" + "node_modules/bootstrap": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz", + "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ], + "peerDependencies": { + "@popperjs/core": "^2.11.8" } }, - "node_modules/fork-ts-checker-webpack-plugin": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.3.tgz", - "integrity": "sha512-SbH/l9ikmMWycd5puHJKTkZJKddF4iRLyW3DeZ08HTI7NGyLS38MXd/KGgeWumQO7YNQbW2u/NtPT2YowbPaGQ==", + "node_modules/boxen": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", + "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", + "dev": true, "dependencies": { - "@babel/code-frame": "^7.8.3", - "@types/json-schema": "^7.0.5", + "ansi-align": "^3.0.0", + "camelcase": "^6.2.0", "chalk": "^4.1.0", - "chokidar": "^3.4.2", - "cosmiconfig": "^6.0.0", - "deepmerge": "^4.2.2", - "fs-extra": "^9.0.0", - "glob": "^7.1.6", - "memfs": "^3.1.2", - "minimatch": "^3.0.4", - "schema-utils": "2.7.0", - "semver": "^7.3.2", - "tapable": "^1.0.0" + "cli-boxes": "^2.2.1", + "string-width": "^4.2.2", + "type-fest": "^0.20.2", + "widest-line": "^3.1.0", + "wrap-ansi": "^7.0.0" }, "engines": { - "node": ">=10", - "yarn": ">=1.0.0" - }, - "peerDependencies": { - "eslint": ">= 6", - "typescript": ">= 2.7", - "vue-template-compiler": "*", - "webpack": ">= 4" + "node": ">=10" }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - }, - "vue-template-compiler": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "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" + "node_modules/boxen/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/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==", - "peerDependencies": { - "ajv": "^6.9.1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/chalk": { + "node_modules/boxen/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" @@ -11869,268 +10694,195 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/cosmiconfig": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", - "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", - "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.7.2" - }, + "node_modules/boxen/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "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": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/fork-ts-checker-webpack-plugin/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==" - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/schema-utils": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", - "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", + "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==", + "devOptional": true, "dependencies": { - "@types/json-schema": "^7.0.4", - "ajv": "^6.12.2", - "ajv-keywords": "^3.4.1" + "fill-range": "^7.1.1" }, "engines": { - "node": ">= 8.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "node": ">=8" } }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/tapable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", - "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "node_modules/brotli": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz", + "integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==", "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fraction.js": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", - "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", - "engines": { - "node": "*" - }, - "funding": { - "type": "patreon", - "url": "https://www.patreon.com/infusion" + "base64-js": "^1.1.2" } }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "engines": { - "node": ">= 0.6" - } + "node_modules/browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", + "dev": true }, - "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==", + "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==", + "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": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "caniuse-lite": "^1.0.30001646", + "electron-to-chromium": "^1.5.4", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" + }, + "bin": { + "browserslist": "cli.js" }, "engines": { - "node": ">=12" + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "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==", - "optional": true, - "peer": true, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" + "node-int64": "^0.4.0" } }, - "node_modules/fs-monkey": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.4.tgz", - "integrity": "sha512-INM/fWAxMICjttnD0DX1rBvinKskj5G1w+oy/pnm9u/tSlnBrzFonJMcalKJ30P8RRsPzKcCG7Q8l0jx5Fh9YQ==" - }, - "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==" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "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==", + "peer": 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" + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" } }, - "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==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "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==" }, - "node_modules/gauge": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", - "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", - "optional": true, + "node_modules/bwip-js": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/bwip-js/-/bwip-js-4.5.1.tgz", + "integrity": "sha512-83yQCKiIftz5YonnsTh6wIkFoHHWl+B/XaGWD1UdRw7aB6XP9JtyYP9n8sRy3m5rzL+Ch/RUPnu28UW0RrPZUA==", + "license": "MIT", "peer": true, - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", - "has-unicode": "^2.0.1", - "signal-exit": "^3.0.7", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "bin": { + "bwip-js": "bin/bwip-js.js" } }, - "node_modules/gaze": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", - "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", - "optional": true, - "peer": true, + "node_modules/cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "dev": true, "dependencies": { - "globule": "^1.0.0" + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" }, "engines": { - "node": ">= 4.0.0" + "node": ">=8" } }, - "node_modules/generic-names": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/generic-names/-/generic-names-4.0.0.tgz", - "integrity": "sha512-ySFolZQfw9FoDb3ed9d80Cm9f0+r7qj+HJkWjeD9RBfpxEVTlVhol+gvaQB/78WbwYfbnNh8nWHHBSlg072y6A==", + "node_modules/cacheable-request/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", "dev": true, "dependencies": { - "loader-utils": "^3.2.0" - } - }, - "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==", + "pump": "^3.0.0" + }, "engines": { - "node": ">=6.9.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "node_modules/cacheable-request/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, "engines": { - "node": "6.* || 8.* || >= 10.*" + "node": ">=8" } }, - "node_modules/get-east-asian-width": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz", - "integrity": "sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==", + "node_modules/cacheable-request/node_modules/normalize-url": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", "dev": true, "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, - "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==", + "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", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" }, "engines": { "node": ">= 0.4" @@ -12139,1570 +10891,1435 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-own-enumerable-property-symbols": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", - "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==" - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "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": ">=8.0.0" + "node": ">=6" } }, - "node_modules/get-stdin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", - "integrity": "sha512-F5aQMywwJ2n85s4hJPTT9RPxGmubonuB10MNYo17/xph174n2MIR33HRguhzVag10O/npM7SPk73LMZNP+FaWw==", - "optional": true, - "peer": true, + "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, "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "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==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "node_modules/caniuse-lite": { + "version": "1.0.30001660", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001660.tgz", + "integrity": "sha512-GacvNTTuATm26qC74pt+ad1fW15mlQ/zuTzzY1ZoIzECTP8HURDfF43kNxPgf7H1jmelCBQTTbBNxdSXOA7Bqg==", + "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/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==", - "dependencies": { - "call-bind": "^1.0.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "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==", + "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": { - "resolve-pkg-maps": "^1.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, - "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + "engines": { + "node": ">=8" } }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "optional": true, - "peer": true, - "dependencies": { - "assert-plus": "^1.0.0" + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "engines": { + "node": ">=10" } }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "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": "*" - }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", "funding": { - "url": "https://github.com/sponsors/isaacs" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "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==", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "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==" + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" }, - "node_modules/global-dirs": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", - "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", - "dev": true, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "devOptional": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], "dependencies": { - "ini": "2.0.0" + "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": ">=10" + "node": ">= 8.10.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "optionalDependencies": { + "fsevents": "~2.3.2" } }, - "node_modules/global-dirs/node_modules/ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "node_modules/ci-info": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", + "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], "engines": { - "node": ">=10" + "node": ">=8" } }, - "node_modules/global-modules": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", - "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", - "dependencies": { - "global-prefix": "^3.0.0" - }, + "node_modules/cjs-module-lexer": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", + "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", + "dev": true + }, + "node_modules/classnames": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", + "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" + }, + "node_modules/cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "dev": true, "engines": { "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/global-prefix": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", - "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, "dependencies": { - "ini": "^1.3.5", - "kind-of": "^6.0.2", - "which": "^1.3.1" + "restore-cursor": "^5.0.0" }, "engines": { - "node": ">=6" - } - }, - "node_modules/global-prefix/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dependencies": { - "isexe": "^2.0.0" + "node": ">=18" }, - "bin": { - "which": "bin/which" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "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==", "engines": { - "node": ">=4" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "node_modules/cli-truncate": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", + "dev": true, "dependencies": { - "define-properties": "^1.1.3" + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "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" - }, + "node_modules/cli-truncate/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": ">=10" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/globule": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.4.tgz", - "integrity": "sha512-OPTIfhMBh7JbBYDpa5b+Q5ptmMWKwcNcFSR/0c6t8V4f3ZAVBEsKNY37QdVqmLRYSMhOUGYrY0QhSoEpzGr/Eg==", - "optional": true, - "peer": true, + "node_modules/cli-truncate/node_modules/emoji-regex": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "dev": true + }, + "node_modules/cli-truncate/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, "dependencies": { - "glob": "~7.1.1", - "lodash": "^4.17.21", - "minimatch": "~3.0.2" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">= 0.10" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/globule/node_modules/glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", - "optional": true, - "peer": true, + "node_modules/cli-truncate/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": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "ansi-regex": "^6.0.1" }, "engines": { - "node": "*" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/globule/node_modules/minimatch": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", - "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", - "optional": true, - "peer": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", "engines": { - "node": "*" + "node": ">= 10" } }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" } }, - "node_modules/got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", - "dev": true, - "dependencies": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" - }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", "engines": { - "node": ">=8.6" + "node": ">=0.8" } }, - "node_modules/got/node_modules/get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", "dev": true, "dependencies": { - "pump": "^3.0.0" + "mimic-response": "^1.0.0" }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", "engines": { "node": ">=6" } }, - "node_modules/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==" - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==" - }, - "node_modules/graphql": { - "version": "16.8.2", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.2.tgz", - "integrity": "sha512-cvVIBILwuoSyD54U4cF/UXDh5yAobhNV/tPygI4lZhgOIJQE/WLWC4waBRb4I6bDVYb3OVx3lfHbaQOEoUD5sg==", + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, "engines": { - "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" } }, - "node_modules/graphql-tag": { - "version": "2.12.6", - "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.12.6.tgz", - "integrity": "sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==", - "dependencies": { - "tslib": "^2.1.0" + "node_modules/coffee-script": { + "version": "1.12.7", + "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.12.7.tgz", + "integrity": "sha512-fLeEhqwymYat/MpTPUjSKHVYYl0ec2mOyALEMLmzr5i1isuG+6jfI2j2d5oBO3VIzgUXgBVIcOT9uH1TFxBckw==", + "deprecated": "CoffeeScript on NPM has moved to \"coffeescript\" (no hyphen)", + "bin": { + "cake": "bin/cake", + "coffee": "bin/coffee" }, "engines": { - "node": ">=10" - }, - "peerDependencies": { - "graphql": "^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" + "node": ">=0.8.0" } }, - "node_modules/graphql-ws": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.16.0.tgz", - "integrity": "sha512-Ju2RCU2dQMgSKtArPbEtsK5gNLnsQyTNIo/T7cZNp96niC1x0KdJNZV0TIoilceBPQwfb5itrGl8pkFeOUMl4A==", - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "graphql": ">=0.11 <=16" - } + "node_modules/collect-v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", + "dev": true }, - "node_modules/gray-matter": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-2.1.1.tgz", - "integrity": "sha512-vbmvP1Fe/fxuT2QuLVcqb2BfK7upGhhbLIt9/owWEvPYrZZEkelLcq2HqzxosV+PQ67dUFLaAeNpH7C4hhICAA==", + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "license": "MIT", "dependencies": { - "ansi-red": "^0.1.1", - "coffee-script": "^1.12.4", - "extend-shallow": "^2.0.1", - "js-yaml": "^3.8.1", - "toml": "^2.3.2" + "color-convert": "^2.0.1", + "color-string": "^1.9.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=12.5.0" } }, - "node_modules/gray-matter/node_modules/extend-shallow": { + "node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { - "is-extendable": "^0.1.0" + "color-name": "~1.1.4" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gray-matter/node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "engines": { - "node": ">=0.10.0" + "node": ">=7.0.0" } }, - "node_modules/gulp-header": { - "version": "1.8.12", - "resolved": "https://registry.npmjs.org/gulp-header/-/gulp-header-1.8.12.tgz", - "integrity": "sha512-lh9HLdb53sC7XIZOYzTXM4lFuXElv3EVkSDhsd7DoJBj7hm+Ni7D3qYbb+Rr8DuM8nRanBvkVO9d7askreXGnQ==", - "deprecated": "Removed event-stream from gulp-header", - "dependencies": { - "concat-with-sourcemaps": "*", - "lodash.template": "^4.4.0", - "through2": "^2.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==" }, - "node_modules/gzip-size": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", - "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "license": "MIT", "dependencies": { - "duplexer": "^0.1.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" } }, - "node_modules/handle-thing": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", - "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==" - }, - "node_modules/har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", - "optional": true, - "peer": true, - "engines": { - "node": ">=4" - } + "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/har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "deprecated": "this library is no longer supported", - "optional": true, - "peer": true, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, "dependencies": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" + "delayed-stream": "~1.0.0" }, "engines": { - "node": ">=6" + "node": ">= 0.8" } }, - "node_modules/har-validator/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "optional": true, - "peer": 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" - }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", "funding": { "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/har-validator/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==", - "optional": true, - "peer": true - }, - "node_modules/hard-rejection": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", - "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", - "optional": true, - "peer": true, + "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": ">=6" + "node": "^12.20.0 || >=14" } }, - "node_modules/harmony-reflect": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/harmony-reflect/-/harmony-reflect-1.6.2.tgz", - "integrity": "sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g==" + "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/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "engines": [ + "node >= 0.8" + ], "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" } }, - "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==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "node_modules/concat-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" }, - "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==", - "engines": { - "node": ">=8" + "node_modules/concat-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "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==", + "node_modules/concat-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/concat-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "safe-buffer": "~5.1.0" } }, - "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==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node_modules/concat-with-sourcemaps": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz", + "integrity": "sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg==", + "dependencies": { + "source-map": "^0.6.1" } }, - "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==", + "node_modules/concat-with-sourcemaps/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==", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.10.0" } }, - "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==", + "node_modules/configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "dev": true, "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "optional": true, - "peer": true - }, - "node_modules/has-yarn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", - "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", - "dev": true, "engines": { "node": ">=8" } }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "node_modules/connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "dev": true, "dependencies": { - "function-bind": "^1.1.2" + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" }, "engines": { - "node": ">= 0.4" - } - }, - "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==", - "bin": { - "he": "bin/he" + "node": ">= 0.10.0" } }, - "node_modules/history": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/history/-/history-5.3.0.tgz", - "integrity": "sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==", + "node_modules/connect/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": { - "@babel/runtime": "^7.7.6" + "ms": "2.0.0" } }, - "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/connect/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/hoist-non-react-statics/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/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/homedir-polyfill": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "node_modules/core-js-compat": { + "version": "3.38.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.38.1.tgz", + "integrity": "sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw==", "dev": true, "dependencies": { - "parse-passwd": "^1.0.0" + "browserslist": "^4.23.3" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" } }, - "node_modules/hoopy": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", - "integrity": "sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==", - "engines": { - "node": ">= 6.0.0" - } + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" }, - "node_modules/hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "optional": true, - "peer": true, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", "dependencies": { - "lru-cache": "^6.0.0" + "@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/hosted-git-info/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "optional": true, - "peer": true, + "node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, "dependencies": { - "yallist": "^4.0.0" + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" }, "engines": { - "node": ">=10" + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" } }, - "node_modules/hosted-git-info/node_modules/yallist": { + "node_modules/cross-fetch": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true, - "peer": true - }, - "node_modules/hpack.js": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", "dependencies": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" + "node-fetch": "^2.6.12" } }, - "node_modules/hpack.js/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "node_modules/hpack.js/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "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": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" } }, - "node_modules/hpack.js/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true, + "engines": { + "node": ">=8" + } }, - "node_modules/hpack.js/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/css-box-model": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz", + "integrity": "sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==", "dependencies": { - "safe-buffer": "~5.1.0" + "tiny-invariant": "^1.0.6" } }, - "node_modules/html-encoding-sniffer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", - "dependencies": { - "whatwg-encoding": "^1.0.5" + "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": ">=10" + "node": ">=4" } }, - "node_modules/html-entities": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.4.0.tgz", - "integrity": "sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/mdevils" - }, - { - "type": "patreon", - "url": "https://patreon.com/mdevils" - } - ] - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==" + "node_modules/cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "dev": true }, - "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==", + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "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" + "cssom": "~0.3.6" }, "engines": { - "node": ">=12" + "node": ">=8" } }, - "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==", - "engines": { - "node": ">= 12" - } + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true }, - "node_modules/html-parse-stringify": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", - "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", + "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/customize-cra": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/customize-cra/-/customize-cra-1.0.0.tgz", + "integrity": "sha512-DbtaLuy59224U+xCiukkxSq8clq++MOtJ1Et7LED1fLszWe88EoblEYFBJ895sB1mC6B4uu3xPT/IjClELhMbA==", "dependencies": { - "void-elements": "3.1.0" + "lodash.flow": "^3.5.0" } }, - "node_modules/html-webpack-plugin": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.3.tgz", - "integrity": "sha512-6YrDKTuqaP/TquFH7h4srYWsZx+x6k6+FbsTm0ziCwGHDP78Unr1r9F/H4+sGmMbX08GQcJ+K64x55b+7VM/jg==", + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", "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" + "internmap": "1 - 2" }, "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/html-webpack-plugin" - }, - "peerDependencies": { - "webpack": "^5.20.0" + "node": ">=12" } }, - "node_modules/html2canvas": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", - "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==", - "dependencies": { - "css-line-break": "^2.1.0", - "text-segmentation": "^1.0.3" - }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", "engines": { - "node": ">=8.0.0" + "node": ">=12" } }, - "node_modules/htmlparser2": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", - "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "entities": "^4.4.0" + "delaunator": "5" + }, + "engines": { + "node": ">=12" } }, - "node_modules/http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "devOptional": true - }, - "node_modules/http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==" + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "engines": { + "node": ">=12" + } }, - "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==", + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "d3-color": "1 - 3" }, "engines": { - "node": ">= 0.8" + "node": ">=12" } }, - "node_modules/http-errors/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", "engines": { - "node": ">= 0.8" + "node": ">=12" } }, - "node_modules/http-parser-js": { - "version": "0.5.8", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", - "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==" - }, - "node_modules/http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", "dependencies": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" }, "engines": { - "node": ">=8.0.0" + "node": ">=12" } }, - "node_modules/http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" + "d3-path": "^3.1.0" }, "engines": { - "node": ">= 6" + "node": ">=12" } }, - "node_modules/http-proxy-middleware": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", - "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", "dependencies": { - "@types/http-proxy": "^1.17.8", - "http-proxy": "^1.18.1", - "is-glob": "^4.0.1", - "is-plain-obj": "^3.0.0", - "micromatch": "^4.0.2" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "@types/express": "^4.17.13" + "d3-array": "2 - 3" }, - "peerDependenciesMeta": { - "@types/express": { - "optional": true - } - } - }, - "node_modules/http-proxy-middleware/node_modules/is-plain-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=12" } }, - "node_modules/http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", - "optional": true, - "peer": true, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" + "d3-time": "1 - 3" }, "engines": { - "node": ">=0.8", - "npm": ">=1.3.7" + "node": ">=12" } }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "node_modules/data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "dev": true, "dependencies": { - "agent-base": "6", - "debug": "4" + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" }, "engines": { - "node": ">= 6" + "node": ">=10" } }, - "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==", + "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": ">=10.17.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/humanize-ms": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", - "optional": true, - "peer": true, + "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": { - "ms": "^2.0.0" + "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/husky": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz", - "integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==", + "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, - "bin": { - "husky": "lib/bin.js" + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" }, "engines": { - "node": ">=14" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/typicode" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/i18next": { - "version": "21.10.0", - "resolved": "https://registry.npmjs.org/i18next/-/i18next-21.10.0.tgz", - "integrity": "sha512-YeuIBmFsGjUfO3qBmMOc0rQaun4mIpGKET5WDwvu8lU7gvwpcariZLNtL0Fzj+zazcHUrlXHiptcFhBMFaxzfg==", - "funding": [ - { - "type": "individual", - "url": "https://locize.com" - }, - { - "type": "individual", - "url": "https://locize.com/i18next.html" - }, - { - "type": "individual", - "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" - } - ], - "dependencies": { - "@babel/runtime": "^7.17.2" - } - }, - "node_modules/i18next-browser-languagedetector": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.0.0.tgz", - "integrity": "sha512-zhXdJXTTCoG39QsrOCiOabnWj2jecouOqbchu3EfhtSHxIB5Uugnm9JaizenOy39h7ne3+fLikIjeW88+rgszw==", + "node_modules/date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "optional": true, + "peer": true, "dependencies": { - "@babel/runtime": "^7.23.2" + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" } }, - "node_modules/i18next-http-backend": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-1.4.5.tgz", - "integrity": "sha512-tLuHWuLWl6CmS07o+UB6EcQCaUjrZ1yhdseIN7sfq0u7phsMePJ8pqlGhIAdRDPF/q7ooyo5MID5DRFBCH+x5w==", - "dependencies": { - "cross-fetch": "3.1.5" - } + + "node_modules/dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==" }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "node_modules/debug": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/ "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" + "ms": "2.1.2" }, "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==", - "engines": { - "node": "^10 || ^12 || >= 14" + "node": ">=6.0" }, - "peerDependencies": { - "postcss": "^8.1.0" + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/idb": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", - "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==" + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", + "dev": true }, - "node_modules/identity-obj-proxy": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz", - "integrity": "sha512-00n6YnVHKrinT9t0d9+5yZC6UBNJANpYEQvL2LlX6Ab9lnmxzIRcEmTPuyGScvl1+jKuCICX1Z0Ab1pPKKdikA==", + "node_modules/decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", + "dev": true, "dependencies": { - "harmony-reflect": "^1.4.6" + "mimic-response": "^1.0.0" }, "engines": { "node": ">=4" } }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "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/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/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, "engines": { - "node": ">= 4" + "node": ">=4.0.0" } }, - "node_modules/immer": { - "version": "9.0.21", - "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", - "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", + "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, + "peer": 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==", + "dependencies": { + "clone": "^1.0.2" + }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/immer" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/immutable": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz", - "integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==", - "devOptional": true + "node_modules/defaults/node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "engines": { + "node": ">=0.8" + } }, - "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==", + "node_modules/defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", + "dev": true + }, + "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": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" }, "engines": { - "node": ">=6" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/import-lazy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==", + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", "dev": true, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "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": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" }, "engines": { - "node": ">=8" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "node_modules/delaunator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", + "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, "engines": { - "node": ">=0.8.19" + "node": ">=0.4.0" } }, - "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==", - "devOptional": true, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", "engines": { - "node": ">=8" + "node": ">=6" } }, - "node_modules/infer-owner": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "optional": true, - "peer": true + "node_modules/detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "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==", + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", "dependencies": { - "once": "^1.3.0", - "wrappy": "1" + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + "node_modules/dfa": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/dfa/-/dfa-1.2.0.tgz", + "integrity": "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==" }, - "node_modules/inquirer": { - "version": "8.2.6", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", - "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", - "dependencies": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.1", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.21", - "mute-stream": "0.0.8", - "ora": "^5.4.1", - "run-async": "^2.4.0", - "rxjs": "^7.5.5", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6", - "wrap-ansi": "^6.0.1" - }, + "node_modules/diacritics-map": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/diacritics-map/-/diacritics-map-0.1.0.tgz", + "integrity": "sha512-3omnDTYrGigU0i4cJjvaKwD52B8aoqyX/NEIkukFFkogBemsIbhSa1O414fpTp5nuszJG6lvQ5vBvDVNCbSsaQ==", "engines": { - "node": ">=12.0.0" + "node": ">=0.8.0" } }, - "node_modules/inquirer/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "node_modules/diff-sequences": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", + "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", + "dev": true, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">= 10.14.2" } }, - "node_modules/inquirer/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==", + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "peer": true, "dependencies": { - "restore-cursor": "^3.1.0" + "esutils": "^2.0.2" }, "engines": { - "node": ">=8" + "node": ">=6.0.0" } }, - "node_modules/inquirer/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==", - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8" - } + "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, + "peer": true }, - "node_modules/inquirer/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/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" } }, - "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==", + "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": { - "es-errors": "^1.3.0", - "hasown": "^2.0.0", - "side-channel": "^1.0.4" + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" }, - "engines": { - "node": ">= 0.4" + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" } }, - "node_modules/internmap": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", - "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", - "engines": { - "node": ">=12" - } + "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/invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "node_modules/domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "dev": true, "dependencies": { - "loose-envify": "^1.0.0" + "webidl-conversions": "^5.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/ip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", - "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==", - "optional": true, - "peer": true - }, - "node_modules/ipaddr.js": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", - "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==", + "node_modules/domexception/node_modules/webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "dev": true, "engines": { - "node": ">= 10" + "node": ">=8" } }, - "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==", + "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": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1" + "domelementtype": "^2.3.0" }, "engines": { - "node": ">= 0.4" + "node": ">= 4" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/fb55/domhandler?sponsor=1" } }, - "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==", + "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": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/fb55/domutils?sponsor=1" } }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "no-case": "^3.0.4", + "tslib": "^2.0.3" } }, - "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==", + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, "dependencies": { - "binary-extensions": "^2.0.0" + "is-obj": "^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==", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, + "node_modules/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", "engines": { - "node": ">= 0.4" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://dotenvx.com" } }, - "node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "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==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "node_modules/duplexer3": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz", + "integrity": "sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==", + "dev": true }, - "node_modules/is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "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.5.19", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.19.tgz", + "integrity": "sha512-kpLJJi3zxTR1U828P+LIUDZ5ohixyo68/IcYOHLqnbTPr/wdgn4i1ECvmALN9E16JPA6cvCG5UG79gVwVdEK5w==" + }, + "node_modules/emittery": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", + "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", "dev": true, - "dependencies": { - "ci-info": "^2.0.0" + "engines": { + "node": ">=10" }, - "bin": { - "is-ci": "bin.js" + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" } }, - "node_modules/is-ci/node_modules/ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true + "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/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "optional": true, + "peer": true, "dependencies": { - "hasown": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "iconv-lite": "^0.6.2" } }, - "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==", + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, "dependencies": { - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "once": "^1.4.0" } }, - "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==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, + "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.4" + "node": ">=0.12" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "bin": { - "is-docker": "cli.js" - }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "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-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "engines": { - "node": ">=0.10.0" + "is-arrayish": "^0.2.1" } }, - "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==", + "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": { - "call-bind": "^1.0.2" + "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/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "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": ">=8" + "node": ">= 0.4" } }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "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": ">=6" + "node": ">= 0.4" } }, - "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==", + "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": { - "has-tostringtag": "^1.0.0" + "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" - }, - "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==", + "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": { - "is-extglob": "^2.1.1" + "es-errors": "^1.3.0" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" } }, - "node_modules/is-installed-globally": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", - "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "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": { - "global-dirs": "^3.0.0", - "is-path-inside": "^3.0.2" + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 0.4" } }, - "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==", - "engines": { - "node": ">=8" + "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/is-lambda": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", - "optional": true, - "peer": true - }, - "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==", + "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" }, @@ -13710,422 +12327,482 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==" - }, - "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==", + "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==", + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, "engines": { - "node": ">= 0.4" + "node": ">=12" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "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/is-npm": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", - "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==", - "dev": true, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=6" } }, - "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==", + "node_modules/escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", + "dev": true, "engines": { - "node": ">=0.12.0" + "node": ">=8" } }, - "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==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, + "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": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "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": ">=8" + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" } }, - "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==", + "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": ">=8" + "node": ">=4.0" } }, - "node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "node_modules/escodegen/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, "optional": true, - "peer": true, "engines": { "node": ">=0.10.0" } }, - "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==", + "node_modules/eslint": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "dev": true, + "license": "MIT", + "peer": true, "dependencies": { - "isobject": "^3.0.1" + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "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" }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==" - }, - "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==", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "bin": { + "eslint": "bin/eslint.js" }, "engines": { - "node": ">= 0.4" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://opencollective.com/eslint" } }, - "node_modules/is-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", - "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", - "engines": { - "node": ">=0.10.0" + "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/is-root": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", - "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==", - "engines": { - "node": ">=6" + "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/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==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "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/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==", + "node_modules/eslint-module-utils": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz", + "integrity": "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==", + "dev": true, "dependencies": { - "call-bind": "^1.0.7" + "debug": "^3.2.7" }, "engines": { - "node": ">= 0.4" + "node": ">=4" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } }, - "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==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "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/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "node_modules/eslint-plugin-import": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.30.0.tgz", + "integrity": "sha512-/mHNE9jINJfiD2EKkg1BKyPyUk4zdnT54YgbOgfjSakWT5oyX/qQLVNTkehyfpcMxZXMy1zyonZ2v7hZTX43Yw==", + "dev": true, "dependencies": { - "has-tostringtag": "^1.0.0" + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.8", + "array.prototype.findlastindex": "^1.2.5", + "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.9.0", + "hasown": "^2.0.2", + "is-core-module": "^2.15.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.0", + "semver": "^6.3.1", + "tsconfig-paths": "^3.15.0" }, "engines": { - "node": ">= 0.4" + "node": ">=4" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" } }, - "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==", + "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": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "ms": "^2.1.1" } }, - "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==", + "node_modules/eslint-plugin-import/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": { - "which-typed-array": "^1.1.14" + "esutils": "^2.0.2" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.10.0" } }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" - }, - "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==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "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/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==", + "node_modules/eslint-plugin-jest": { + "version": "28.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-28.8.0.tgz", + "integrity": "sha512-Tubj1hooFxCl52G4qQu0edzV/+EZzPUeN8p2NnW5uu4fbDs+Yo7+qDVDc4/oG3FbCqEBmu/OC3LSsyiU22oghw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/utils": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, "engines": { - "node": ">= 0.4" + "node": "^16.10.0 || ^18.12.0 || >=20.0.0" }, - "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==", - "dependencies": { - "call-bind": "^1.0.2" + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^6.0.0 || ^7.0.0 || ^8.0.0", + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0", + "jest": "*" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + }, + "jest": { + "optional": true + } } }, - "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==", + "node_modules/eslint-plugin-prettier": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.1.tgz", + "integrity": "sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==", + "dev": true, "dependencies": { - "call-bind": "^1.0.7", - "get-intrinsic": "^1.2.4" + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.9.1" }, "engines": { - "node": ">= 0.4" + "node": "^14.18.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "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/is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "node_modules/eslint-plugin-react": { + "version": "7.37.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.1.tgz", + "integrity": "sha512-xwTnwDqzbDRA8uJ7BMxPs/EXRB3i8ZfnOIp8BsxEQkT0nHPp+WWceqGgo6rKb9ctNi8GJLDT4Go5HAWELa/WMg==", "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", "dependencies": { - "is-docker": "^2.0.0" + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.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": ">=8" + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, - "node_modules/is-yarn-global": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", - "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", - "dev": true - }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" - }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "node_modules/eslint-plugin-react/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/isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", - "optional": true, - "peer": true - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "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": ">=8" + "node": ">=4.0" } }, - "node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "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": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" }, - "engines": { - "node": ">=8" + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/istanbul-lib-instrument/node_modules/semver": { + "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/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "node_modules/eslint-plugin-tsdoc": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-tsdoc/-/eslint-plugin-tsdoc-0.3.0.tgz", + "integrity": "sha512-0MuFdBrrJVBjT/gyhkP2BqpD0np1NxNLfQ38xXDlSs/KVVpKI2A6vN7jx2Rve/CyUsvOsMGwp9KKrinv7q9g3A==", + "dev": true, "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" + "@microsoft/tsdoc": "0.15.0", + "@microsoft/tsdoc-config": "0.17.0" } }, - "node_modules/istanbul-lib-source-maps/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==", + "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, + "license": "Apache-2.0", "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, - "engines": { - "node": ">=8" - } - }, - "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==", - "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" + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/jake": { - "version": "10.8.7", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz", - "integrity": "sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==", + "node_modules/eslint/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, + "peer": true, "dependencies": { - "async": "^3.2.3", - "chalk": "^4.0.2", - "filelist": "^1.0.4", - "minimatch": "^3.1.2" - }, - "bin": { - "jake": "bin/cli.js" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" }, - "engines": { - "node": ">=10" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/jake/node_modules/chalk": { + "node_modules/eslint/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, + "peer": true + }, + "node_modules/eslint/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, + "peer": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -14137,3548 +12814,2710 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", - "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "license": "BSD-2-Clause", + "peer": true, "dependencies": { - "@jest/core": "^27.5.1", - "import-local": "^3.0.2", - "jest-cli": "^27.5.1" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" }, - "bin": { - "jest": "bin/jest.js" + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.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, + "license": "BSD-2-Clause", + "peer": true, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "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, + "peer": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + "engines": { + "node": ">=10" }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-changed-files": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.5.1.tgz", - "integrity": "sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==", + "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, + "peer": true, "dependencies": { - "@jest/types": "^27.5.1", - "execa": "^5.0.0", - "throat": "^6.0.1" + "is-glob": "^4.0.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=10.13.0" } }, - "node_modules/jest-circus": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.5.1.tgz", - "integrity": "sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==", + "node_modules/eslint/node_modules/globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dev": true, + "peer": true, "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "expect": "^27.5.1", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3", - "throat": "^6.0.1" + "type-fest": "^0.20.2" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-circus/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/eslint/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==", + "dev": true, + "peer": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eslint/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, + "peer": true + }, + "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, + "peer": true, + "dependencies": { + "p-locate": "^5.0.0" }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-circus/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/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, + "peer": true, "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" + "yocto-queue": "^0.1.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-circus/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/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, + "peer": true, + "dependencies": { + "p-limit": "^3.0.2" + }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-circus/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==" - }, - "node_modules/jest-cli": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", - "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", - "dependencies": { - "@jest/core": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "import-local": "^3.0.2", - "jest-config": "^27.5.1", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", - "prompts": "^2.0.1", - "yargs": "^16.2.0" - }, - "bin": { - "jest": "bin/jest.js" - }, + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "peer": true, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + "node": ">=10" }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-cli/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "license": "BSD-2-Clause", + "peer": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" }, "engines": { - "node": ">=10" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://opencollective.com/eslint" } }, - "node_modules/jest-config": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", - "integrity": "sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==", - "dependencies": { - "@babel/core": "^7.8.0", - "@jest/test-sequencer": "^27.5.1", - "@jest/types": "^27.5.1", - "babel-jest": "^27.5.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.1", - "graceful-fs": "^4.2.9", - "jest-circus": "^27.5.1", - "jest-environment-jsdom": "^27.5.1", - "jest-environment-node": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-jasmine2": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-runner": "^27.5.1", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" + "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==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "ts-node": { - "optional": true - } + "node": ">=4" } }, - "node_modules/jest-config/node_modules/babel-jest": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", - "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "peer": true, "dependencies": { - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^27.5.1", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" + "estraverse": "^5.1.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" + "node": ">=0.10" } }, - "node_modules/jest-config/node_modules/babel-plugin-jest-hoist": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz", - "integrity": "sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==", - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.0.0", - "@types/babel__traverse": "^7.0.6" - }, + "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, + "peer": true, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=4.0" } }, - "node_modules/jest-config/node_modules/babel-preset-jest": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz", - "integrity": "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==", + "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, + "peer": true, "dependencies": { - "babel-plugin-jest-hoist": "^27.5.1", - "babel-preset-current-node-syntax": "^1.0.0" + "estraverse": "^5.2.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node": ">=4.0" } }, - "node_modules/jest-config/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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, + "peer": true, + "engines": { + "node": ">=4.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" + } + }, + "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": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "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/chalk/chalk?sponsor=1" + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/jest-config/node_modules/jest-environment-node": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.5.1.tgz", - "integrity": "sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==", - "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1" - }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">= 0.8.0" } }, - "node_modules/jest-config/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/expand-range": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha512-AFASGfIlnIbkKPQwX1yHaDjFvh/1gyKJODme52V6IORh69uEYgZp0o9C+qsIGNVEiuuhQU0CSSl++Rlegg1qvA==", "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" + "fill-range": "^2.1.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=0.10.0" } }, - "node_modules/jest-config/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==", - "engines": { - "node": ">=10" + "node_modules/expand-range/node_modules/fill-range": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", + "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", + "dependencies": { + "is-number": "^2.1.0", + "isobject": "^2.0.0", + "randomatic": "^3.0.0", + "repeat-element": "^1.1.2", + "repeat-string": "^1.5.2" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/jest-config/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==" - }, - "node_modules/jest-diff": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", - "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", - "dev": true, + "node_modules/expand-range/node_modules/is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha512-QUzH43Gfb9+5yckcrSA0VBDwEtDUchrk4F6tfJZQuNzDJbEDB9cZNzSfXGQ1jqmdDY/kl41lUOWM9syA8z8jlg==", "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" + "kind-of": "^3.0.2" }, "engines": { - "node": ">= 10.14.2" + "node": ">=0.10.0" } }, - "node_modules/jest-diff/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/expand-range/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/expand-range/node_modules/isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "isarray": "1.0.0" }, "engines": { - "node": ">=10" + "node": ">=0.10.0" + } + }, + "node_modules/expand-range/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dependencies": { + "is-buffer": "^1.1.5" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/jest-diff/node_modules/jest-get-type": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", - "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", + "node_modules/expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", "dev": true, + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, "engines": { - "node": ">= 10.14.2" + "node": ">=0.10.0" } }, - "node_modules/jest-docblock": { + "node_modules/expect": { "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz", - "integrity": "sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", + "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "dev": true, "dependencies": { - "detect-newline": "^3.0.0" + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-docblock/node_modules/detect-newline": { + "node_modules/external-editor": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/jest-each": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.5.1.tgz", - "integrity": "sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==", + "node_modules/external-editor/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==", "dependencies": { - "@jest/types": "^27.5.1", - "chalk": "^4.0.0", - "jest-get-type": "^27.5.1", - "jest-util": "^27.5.1", - "pretty-format": "^27.5.1" + "safer-buffer": ">= 2.1.2 < 3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=0.10.0" } }, - "node_modules/jest-each/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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==" + }, + "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, + "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@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": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=8.6.0" } }, - "node_modules/jest-each/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/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, + "peer": true + }, + "node_modules/fast-xml-parser": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz", + "integrity": "sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + }, + { + "type": "paypal", + "url": "https://paypal.me/naturalintelligence" + } + ], + "license": "MIT", + "peer": true, "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" + "strnum": "^1.0.5" }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "bin": { + "fxparser": "src/cli/cli.js" } }, - "node_modules/jest-each/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==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" } }, - "node_modules/jest-each/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==" + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "dependencies": { + "bser": "2.1.1" + } }, - "node_modules/jest-environment-jsdom": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz", - "integrity": "sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==", + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1", - "jsdom": "^16.6.0" + "escape-string-regexp": "^1.0.5" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-get-type": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", - "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "node_modules/figures/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": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=0.8.0" } }, - "node_modules/jest-haste-map": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", - "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "peer": true, "dependencies": { - "@jest/types": "^27.5.1", - "@types/graceful-fs": "^4.1.2", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^27.5.1", - "jest-serializer": "^27.5.1", - "jest-util": "^27.5.1", - "jest-worker": "^27.5.1", - "micromatch": "^4.0.4", - "walker": "^1.0.7" + "flat-cache": "^3.0.4" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" + "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/jest-jasmine2": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz", - "integrity": "sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==", + "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==", + "devOptional": true, "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/source-map": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "expect": "^27.5.1", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "pretty-format": "^27.5.1", - "throat": "^6.0.1" + "to-regex-range": "^5.0.1" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=8" } }, - "node_modules/jest-jasmine2/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">= 0.8" } }, - "node_modules/jest-jasmine2/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/finalhandler/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": { - "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" + "ms": "2.0.0" } }, - "node_modules/jest-jasmine2/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==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node_modules/finalhandler/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/find-node-modules": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/find-node-modules/-/find-node-modules-2.1.3.tgz", + "integrity": "sha512-UC2I2+nx1ZuOBclWVNdcnbDR5dlrOdVb7xNjmT/lHE+LsgztWks3dG7boJ37yTS/venXw84B/mAW9uHVoC5QRg==", + "dev": true, + "dependencies": { + "findup-sync": "^4.0.0", + "merge": "^2.1.1" } }, - "node_modules/jest-jasmine2/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==" + "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/jest-leak-detector": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz", - "integrity": "sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==", + "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": { - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=8" } }, - "node_modules/jest-leak-detector/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==", - "engines": { - "node": ">=10" + "node_modules/findup-sync": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", + "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==", + "dev": true, + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^4.0.2", + "resolve-dir": "^1.0.1" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "engines": { + "node": ">= 8" } }, - "node_modules/jest-leak-detector/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/flag-icons": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/flag-icons/-/flag-icons-7.2.3.tgz", + "integrity": "sha512-X2gUdteNuqdNqob2KKTJTS+ZCvyWeLCtDz9Ty8uJP17Y4o82Y+U/Vd4JNrdwTAjagYsRznOn9DZ+E/Q52qbmqg==" + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "peer": true, "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" + "flatted": "^3.1.0", + "rimraf": "^3.0.2" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/jest-leak-detector/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==" - }, - "node_modules/jest-localstorage-mock": { - "version": "2.4.26", - "resolved": "https://registry.npmjs.org/jest-localstorage-mock/-/jest-localstorage-mock-2.4.26.tgz", - "integrity": "sha512-owAJrYnjulVlMIXOYQIPRCCn3MmqI3GzgfZCXdD3/pmwrIvFMXcKVWZ+aMc44IzaASapg0Z4SEFxR+v5qxDA2w==", + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true, - "engines": { - "node": ">=6.16.0" + "peer": true + }, + "node_modules/fontkit": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fontkit/-/fontkit-2.0.2.tgz", + "integrity": "sha512-jc4k5Yr8iov8QfS6u8w2CnHWVmbOGtdBtOXMze5Y+QD966Rx6PEVWXSEGwXlsDlKtu1G12cJjcsybnqhSk/+LA==", + "dependencies": { + "@swc/helpers": "^0.4.2", + "brotli": "^1.3.2", + "clone": "^2.1.2", + "dfa": "^1.2.0", + "fast-deep-equal": "^3.1.3", + "restructure": "^3.0.0", + "tiny-inflate": "^1.0.3", + "unicode-properties": "^1.4.0", + "unicode-trie": "^2.0.0" } }, - "node_modules/jest-location-mock": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/jest-location-mock/-/jest-location-mock-2.0.0.tgz", - "integrity": "sha512-loakfclgY/y65/2i4s0fcdlZY3hRPfwNnmzRsGFQYQryiaow2DEIGTLXIPI8cAO1Is36xsVLVkIzgvhQ+FXHdw==", + "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": { - "@jedmao/location": "^3.0.0", - "jest-diff": "^29.6.4" - }, + "is-callable": "^1.1.3" + } + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", "engines": { - "node": "^16.10.0 || >=18.0.0" + "node": ">=0.10.0" } }, - "node_modules/jest-location-mock/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==", + "node_modules/form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", "dev": true, "dependencies": { - "@sinclair/typebox": "^0.27.8" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 6" } }, - "node_modules/jest-location-mock/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==", + "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/jest-location-mock/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-location-mock/node_modules/diff-sequences": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", - "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "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, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-location-mock/node_modules/jest-diff": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", - "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "node_modules/generic-names": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/generic-names/-/generic-names-4.0.0.tgz", + "integrity": "sha512-ySFolZQfw9FoDb3ed9d80Cm9f0+r7qj+HJkWjeD9RBfpxEVTlVhol+gvaQB/78WbwYfbnNh8nWHHBSlg072y6A==", "dev": true, "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.6.3", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "loader-utils": "^3.2.0" } }, - "node_modules/jest-location-mock/node_modules/jest-get-type": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", - "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", - "dev": true, + "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": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=6.9.0" } }, - "node_modules/jest-location-mock/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==", + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "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": "6.* || 8.* || >= 10.*" } }, - "node_modules/jest-location-mock/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/get-east-asian-width": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz", + "integrity": "sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==", "dev": true, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-matcher-utils": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", - "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "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": { - "chalk": "^4.0.0", - "jest-diff": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" + "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": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-matcher-utils/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=8.0.0" } }, - "node_modules/jest-matcher-utils/node_modules/diff-sequences": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", - "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "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.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-matcher-utils/node_modules/jest-diff": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", - "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "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": { - "chalk": "^4.0.0", - "diff-sequences": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-matcher-utils/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/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": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" + "resolve-pkg-maps": "^1.0.0" }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, - "node_modules/jest-matcher-utils/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/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "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": ">=10" + "node": "*" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/jest-matcher-utils/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==" - }, - "node_modules/jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "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==", + "devOptional": true, "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" + "is-glob": "^4.0.1" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">= 6" } }, - "node_modules/jest-message-util/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/global-dirs": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", + "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", + "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "ini": "2.0.0" }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-message-util/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==", - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, + "node_modules/global-dirs/node_modules/ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "dev": true, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=10" } }, - "node_modules/jest-message-util/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/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": ">=10" + "node": ">=4" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-message-util/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==" + "node_modules/globrex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", + "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==" }, - "node_modules/jest-mock": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", - "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", - "dependencies": { - "@jest/types": "^27.5.1", - "@types/node": "*" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } - } - }, - "node_modules/jest-preview": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/jest-preview/-/jest-preview-0.3.1.tgz", - "integrity": "sha512-gRR4shnXFSh8tdNaIncJC98d1zXD7w7LA52HQC0bu0DsPb+FXVEg+NQh9GTbO+n6/SCgcZNQAVt4MeCfsIkBPA==", + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", "dev": true, - "hasInstallScript": true, "dependencies": { - "@svgr/core": "^6.2.1", - "camelcase": "^6.3.0", - "chalk": "^4.1.2", - "chokidar": "^3.5.3", - "commander": "^9.2.0", - "connect": "^3.7.0", - "find-node-modules": "^2.1.3", - "open": "^8.4.0", - "postcss-import": "^14.1.0", - "postcss-load-config": "^4.0.1", - "sirv": "^2.0.2", - "slash": "^3.0.0", - "string-hash": "^1.1.3", - "update-notifier": "^5.1.0", - "ws": "^8.5.0" - }, - "bin": { - "jest-preview": "cli/index.js" + "get-intrinsic": "^1.1.3" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/jest-preview" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-preview/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "node_modules/got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", "dev": true, - "engines": { - "node": ">=10" + "dependencies": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=8.6" } }, - "node_modules/jest-preview/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/got/node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "pump": "^3.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=6" } }, - "node_modules/jest-regex-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", - "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } + "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/jest-resolve": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz", - "integrity": "sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==", - "dependencies": { - "@jest/types": "^27.5.1", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", - "resolve": "^1.20.0", - "resolve.exports": "^1.1.0", - "slash": "^3.0.0" - }, + "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/graphql": { + "version": "16.9.0", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.9.0.tgz", + "integrity": "sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==", "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" } }, - "node_modules/jest-resolve-dependencies": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz", - "integrity": "sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==", + "node_modules/graphql-tag": { + "version": "2.12.6", + "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.12.6.tgz", + "integrity": "sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==", "dependencies": { - "@jest/types": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-snapshot": "^27.5.1" + "tslib": "^2.1.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=10" + }, + "peerDependencies": { + "graphql": "^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, - "node_modules/jest-resolve/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "node_modules/graphql-ws": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.16.0.tgz", + "integrity": "sha512-Ju2RCU2dQMgSKtArPbEtsK5gNLnsQyTNIo/T7cZNp96niC1x0KdJNZV0TIoilceBPQwfb5itrGl8pkFeOUMl4A==", "engines": { "node": ">=10" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "peerDependencies": { + "graphql": ">=0.11 <=16" } }, - "node_modules/jest-runner": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.5.1.tgz", - "integrity": "sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==", + "node_modules/gray-matter": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-2.1.1.tgz", + "integrity": "sha512-vbmvP1Fe/fxuT2QuLVcqb2BfK7upGhhbLIt9/owWEvPYrZZEkelLcq2HqzxosV+PQ67dUFLaAeNpH7C4hhICAA==", "dependencies": { - "@jest/console": "^27.5.1", - "@jest/environment": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.8.1", - "graceful-fs": "^4.2.9", - "jest-docblock": "^27.5.1", - "jest-environment-jsdom": "^27.5.1", - "jest-environment-node": "^27.5.1", - "jest-haste-map": "^27.5.1", - "jest-leak-detector": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-util": "^27.5.1", - "jest-worker": "^27.5.1", - "source-map-support": "^0.5.6", - "throat": "^6.0.1" + "ansi-red": "^0.1.1", + "coffee-script": "^1.12.4", + "extend-shallow": "^2.0.1", + "js-yaml": "^3.8.1", + "toml": "^2.3.2" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=0.10.0" } }, - "node_modules/jest-runner/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/gray-matter/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "is-extendable": "^0.1.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=0.10.0" } }, - "node_modules/jest-runner/node_modules/jest-environment-node": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.5.1.tgz", - "integrity": "sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==", - "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1" - }, + "node_modules/gray-matter/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=0.10.0" } }, - "node_modules/jest-runtime": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.5.1.tgz", - "integrity": "sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==", + "node_modules/gulp-header": { + "version": "1.8.12", + "resolved": "https://registry.npmjs.org/gulp-header/-/gulp-header-1.8.12.tgz", + "integrity": "sha512-lh9HLdb53sC7XIZOYzTXM4lFuXElv3EVkSDhsd7DoJBj7hm+Ni7D3qYbb+Rr8DuM8nRanBvkVO9d7askreXGnQ==", + "deprecated": "Removed event-stream from gulp-header", "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/fake-timers": "^27.5.1", - "@jest/globals": "^27.5.1", - "@jest/source-map": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "execa": "^5.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-mock": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-runtime/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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-serializer": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", - "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", - "dependencies": { - "@types/node": "*", - "graceful-fs": "^4.2.9" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-snapshot": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.5.1.tgz", - "integrity": "sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==", - "dependencies": { - "@babel/core": "^7.7.2", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.0.0", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/babel__traverse": "^7.0.4", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^27.5.1", - "graceful-fs": "^4.2.9", - "jest-diff": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-haste-map": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-util": "^27.5.1", - "natural-compare": "^1.4.0", - "pretty-format": "^27.5.1", - "semver": "^7.3.2" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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-snapshot/node_modules/diff-sequences": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", - "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/jest-diff": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", - "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-snapshot/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==", - "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/jest-snapshot/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==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-snapshot/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==" - }, - "node_modules/jest-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", - "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", - "dependencies": { - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-util/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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-validate": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", - "integrity": "sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==", - "dependencies": { - "@jest/types": "^27.5.1", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^27.5.1", - "leven": "^3.1.0", - "pretty-format": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-validate/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/jest-validate/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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-validate/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==", - "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/jest-validate/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==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-validate/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==" - }, - "node_modules/jest-watch-typeahead": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/jest-watch-typeahead/-/jest-watch-typeahead-1.1.0.tgz", - "integrity": "sha512-Va5nLSJTN7YFtC2jd+7wsoe1pNe5K4ShLux/E5iHEwlB9AxaxmggY7to9KUqKojhaJw3aXqt5WAb4jGPOolpEw==", - "dependencies": { - "ansi-escapes": "^4.3.1", - "chalk": "^4.0.0", - "jest-regex-util": "^28.0.0", - "jest-watcher": "^28.0.0", - "slash": "^4.0.0", - "string-length": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "jest": "^27.0.0 || ^28.0.0" - } - }, - "node_modules/jest-watch-typeahead/node_modules/@jest/console": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-28.1.3.tgz", - "integrity": "sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw==", - "dependencies": { - "@jest/types": "^28.1.3", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^28.1.3", - "jest-util": "^28.1.3", - "slash": "^3.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-watch-typeahead/node_modules/@jest/console/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-watch-typeahead/node_modules/@jest/test-result": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-28.1.3.tgz", - "integrity": "sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg==", - "dependencies": { - "@jest/console": "^28.1.3", - "@jest/types": "^28.1.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-watch-typeahead/node_modules/@jest/types": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", - "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", - "dependencies": { - "@jest/schemas": "^28.1.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": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-watch-typeahead/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-watch-typeahead/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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-watch-typeahead/node_modules/emittery": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", - "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "node_modules/jest-watch-typeahead/node_modules/jest-message-util": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", - "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^28.1.3", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^28.1.3", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-watch-typeahead/node_modules/jest-message-util/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-watch-typeahead/node_modules/jest-regex-util": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", - "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-watch-typeahead/node_modules/jest-util": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", - "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", - "dependencies": { - "@jest/types": "^28.1.3", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-watch-typeahead/node_modules/jest-watcher": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-28.1.3.tgz", - "integrity": "sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g==", - "dependencies": { - "@jest/test-result": "^28.1.3", - "@jest/types": "^28.1.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.10.2", - "jest-util": "^28.1.3", - "string-length": "^4.0.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-watch-typeahead/node_modules/jest-watcher/node_modules/string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-watch-typeahead/node_modules/jest-watcher/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==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-watch-typeahead/node_modules/pretty-format": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", - "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", - "dependencies": { - "@jest/schemas": "^28.1.3", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-watch-typeahead/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==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-watch-typeahead/node_modules/slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-watch-typeahead/node_modules/string-length": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-5.0.1.tgz", - "integrity": "sha512-9Ep08KAMUn0OadnVaBuRdE2l615CQ508kr0XMadjClfYpdCyvrbFp6Taebo8yyxokQ4viUd/xPPUA4FGgUa0ow==", - "dependencies": { - "char-regex": "^2.0.0", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-watch-typeahead/node_modules/string-length/node_modules/char-regex": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-2.0.1.tgz", - "integrity": "sha512-oSvEeo6ZUD7NepqAat3RqoucZ5SeqLJgOvVIwkafu6IP3V0pO38s/ypdVUmDDK6qIIHNlYHJAKX9E7R7HoKElw==", - "engines": { - "node": ">=12.20" - } - }, - "node_modules/jest-watch-typeahead/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==", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/jest-watch-typeahead/node_modules/strip-ansi/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==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/jest-watcher": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.5.1.tgz", - "integrity": "sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==", - "dependencies": { - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "jest-util": "^27.5.1", - "string-length": "^4.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-watcher/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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-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==", - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "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==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/jiti": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.19.1.tgz", - "integrity": "sha512-oVhqoRDaBXf7sjkll95LHVS6Myyyb1zaunVwk4Z0+WPSW4gjS0pl01zYKHScTuyEhQsFxV5L4DR5r+YqSyqyyg==", - "bin": { - "jiti": "bin/jiti.js" - } - }, - "node_modules/jju": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", - "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", - "dev": true - }, - "node_modules/js-base64": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz", - "integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==", - "optional": true, - "peer": true - }, - "node_modules/js-cookie": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", - "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", - "engines": { - "node": ">=14" - } - }, - "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": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "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==", - "optional": true, - "peer": true - }, - "node_modules/jsdom": { - "version": "16.7.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", - "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", - "dependencies": { - "abab": "^2.0.5", - "acorn": "^8.2.4", - "acorn-globals": "^6.0.0", - "cssom": "^0.4.4", - "cssstyle": "^2.3.0", - "data-urls": "^2.0.0", - "decimal.js": "^10.2.1", - "domexception": "^2.0.1", - "escodegen": "^2.0.0", - "form-data": "^3.0.0", - "html-encoding-sniffer": "^2.0.1", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.0", - "parse5": "6.0.1", - "saxes": "^5.0.1", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.0.0", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^2.0.0", - "webidl-conversions": "^6.1.0", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.5.0", - "ws": "^7.4.6", - "xml-name-validator": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "canvas": "^2.5.0" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, - "node_modules/jsdom/node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" - }, - "node_modules/jsdom/node_modules/ws": { - "version": "7.5.9", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", - "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "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.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==", - "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": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" - }, - "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==" - }, - "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==" - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "optional": true, - "peer": 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/jsonc-parser": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", - "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", - "peer": true - }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/jsonpointer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", - "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "optional": true, - "peer": true, - "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/jsx-ast-utils": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.4.tgz", - "integrity": "sha512-fX2TVdCViod6HwKEtSWGHs57oFhVfCMwieb9PuRDgjDPh5XeqJiHFFFJCHxU5cnTc3Bu/GRL+kPiFmw8XWOfKw==", - "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": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.0" - } - }, - "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==", - "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==", - "engines": { - "node": ">=6" - } - }, - "node_modules/klona": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", - "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/language-subtag-registry": { - "version": "0.3.22", - "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", - "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==" - }, - "node_modules/language-tags": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", - "integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==", - "dependencies": { - "language-subtag-registry": "~0.3.2" - } - }, - "node_modules/latest-version": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", - "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", - "dev": true, - "dependencies": { - "package-json": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/launch-editor": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.0.tgz", - "integrity": "sha512-JpDCcQnyAAzZZaZ7vEiSqL690w7dAEyLao+KC96zBplnYbJS7TYNjvM3M7y3dGz+v7aIsJk3hllWuc0kWAjyRQ==", - "dependencies": { - "picocolors": "^1.0.0", - "shell-quote": "^1.7.3" - } - }, - "node_modules/lazy-cache": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-2.0.2.tgz", - "integrity": "sha512-7vp2Acd2+Kz4XkzxGxaB1FWOi8KjWIWsgdfD5MCb86DWvlLqhRPM+d6Pro3iNEL5VT9mstz5hKAlcd+QR6H3aA==", - "dependencies": { - "set-getter": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "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==", - "engines": { - "node": ">=6" + "concat-with-sourcemaps": "*", + "lodash.template": "^4.4.0", + "through2": "^2.0.0" } }, - "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==", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" + "node_modules/harmony-reflect": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/harmony-reflect/-/harmony-reflect-1.6.2.tgz", + "integrity": "sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g==", + "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/lilconfig": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", - "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "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==", "engines": { - "node": ">=10" + "node": ">=8" } }, - "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/lint-staged": { - "version": "15.2.7", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.7.tgz", - "integrity": "sha512-+FdVbbCZ+yoh7E/RosSdqKJyUM2OEjTciH0TFNkawKgvFp1zbGlEC39RADg+xKBG1R4mhoH2j85myBQZ5wR+lw==", + "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": { - "chalk": "~5.3.0", - "commander": "~12.1.0", - "debug": "~4.3.4", - "execa": "~8.0.1", - "lilconfig": "~3.1.1", - "listr2": "~8.2.1", - "micromatch": "~4.0.7", - "pidtree": "~0.6.0", - "string-argv": "~0.3.2", - "yaml": "~2.4.2" - }, - "bin": { - "lint-staged": "bin/lint-staged.js" - }, - "engines": { - "node": ">=18.12.0" + "es-define-property": "^1.0.0" }, "funding": { - "url": "https://opencollective.com/lint-staged" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/lint-staged/node_modules/chalk": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", - "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "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": "^12.17.0 || ^14.13 || >=16.0.0" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/lint-staged/node_modules/commander": { - "version": "12.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", - "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "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": ">=18" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/lint-staged/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==", + "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": { - "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" + "has-symbols": "^1.0.3" }, "engines": { - "node": ">=16.17" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/lint-staged/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==", + "node_modules/has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", "dev": true, "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, - "node_modules/lint-staged/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, + "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": ">=16.17.0" + "node": ">= 0.4" } }, - "node_modules/lint-staged/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" + "node_modules/hast-util-to-html": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.2.tgz", + "integrity": "sha512-RP5wNpj5nm1Z8cloDv4Sl4RS8jH5HYa0v93YB6Wb4poEzgMo/dAAL0KcT4974dCjcNG5pkLqTImeFHHCwwfY3g==", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/lint-staged/node_modules/lilconfig": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", - "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", - "dev": true, - "engines": { - "node": ">=14" + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "dependencies": { + "@types/hast": "^3.0.0" }, "funding": { - "url": "https://github.com/sponsors/antonk52" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/lint-staged/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==", + "node_modules/history": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/history/-/history-5.3.0.tgz", + "integrity": "sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==", + "dependencies": { + "@babel/runtime": "^7.7.6" + } + }, + "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/hoist-non-react-statics/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/homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", "dev": true, - "engines": { - "node": ">=12" + "dependencies": { + "parse-passwd": "^1.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/lint-staged/node_modules/npm-run-path": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.2.0.tgz", - "integrity": "sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==", + "node_modules/html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", "dev": true, "dependencies": { - "path-key": "^4.0.0" + "whatwg-encoding": "^1.0.5" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=10" + } + }, + "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==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ] + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/html-parse-stringify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", + "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", + "dependencies": { + "void-elements": "3.1.0" + } + }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">= 6" } }, - "node_modules/lint-staged/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==", + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", "dev": true, "dependencies": { - "mimic-fn": "^4.0.0" + "agent-base": "6", + "debug": "4" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 6" } }, - "node_modules/lint-staged/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==", + "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": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=10.17.0" } }, - "node_modules/lint-staged/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==", + "node_modules/husky": { + "version": "9.1.6", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.6.tgz", + "integrity": "sha512-sqbjZKK7kf44hfdE94EoX8MZNk0n7HeW37O4YrVGCF4wzgQjp+akPAkfUK5LZ6KuR/6sqeAVuXHji+RzQgOn5A==", "dev": true, + "bin": { + "husky": "bin.js" + }, "engines": { - "node": ">=14" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/typicode" } }, - "node_modules/lint-staged/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/i18next": { + "version": "23.15.1", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.15.1.tgz", + "integrity": "sha512-wB4abZ3uK7EWodYisHl/asf8UYEhrI/vj/8aoSsrj/ZDxj4/UXPOa1KvFt1Fq5hkUHquNqwFlDprmjZ8iySgYA==", + "funding": [ + { + "type": "individual", + "url": "https://locize.com" + }, + { + "type": "individual", + "url": "https://locize.com/i18next.html" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + } + ], + "dependencies": { + "@babel/runtime": "^7.23.2" } }, - "node_modules/lint-staged/node_modules/yaml": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.5.tgz", - "integrity": "sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==", - "dev": true, - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14" + "node_modules/i18next-browser-languagedetector": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.0.0.tgz", + "integrity": "sha512-zhXdJXTTCoG39QsrOCiOabnWj2jecouOqbchu3EfhtSHxIB5Uugnm9JaizenOy39h7ne3+fLikIjeW88+rgszw==", + "dependencies": { + "@babel/runtime": "^7.23.2" } }, - "node_modules/list-item": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/list-item/-/list-item-1.1.1.tgz", - "integrity": "sha512-S3D0WZ4J6hyM8o5SNKWaMYB1ALSacPZ2nHGEuCjmHZ+dc03gFeNZoNDcqfcnO4vDhTZmNrqrpYZCdXsRh22bzw==", + "node_modules/i18next-http-backend": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-2.6.1.tgz", + "integrity": "sha512-rCilMAnlEQNeKOZY1+x8wLM5IpYOj10guGvEpeC59tNjj6MMreLIjIW8D1RclhD3ifLwn6d/Y9HEM1RUE6DSog==", "dependencies": { - "expand-range": "^1.8.1", - "extend-shallow": "^2.0.1", - "is-number": "^2.1.0", - "repeat-string": "^1.5.2" - }, - "engines": { - "node": ">=0.10.0" + "cross-fetch": "4.0.0" } }, - "node_modules/list-item/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "optional": true, + "peer": true, "dependencies": { - "is-extendable": "^0.1.0" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/list-item/node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "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": ">=0.10.0" + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" } }, - "node_modules/list-item/node_modules/is-number": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", - "integrity": "sha512-QUzH43Gfb9+5yckcrSA0VBDwEtDUchrk4F6tfJZQuNzDJbEDB9cZNzSfXGQ1jqmdDY/kl41lUOWM9syA8z8jlg==", + "node_modules/identity-obj-proxy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz", + "integrity": "sha512-00n6YnVHKrinT9t0d9+5yZC6UBNJANpYEQvL2LlX6Ab9lnmxzIRcEmTPuyGScvl1+jKuCICX1Z0Ab1pPKKdikA==", + "dev": true, "dependencies": { - "kind-of": "^3.0.2" + "harmony-reflect": "^1.4.6" }, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/list-item/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "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.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/immer": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.1.tgz", + "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/immutable": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz", + "integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==", + "devOptional": true + }, + "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": { - "is-buffer": "^1.1.5" + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/listr2": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.1.tgz", - "integrity": "sha512-irTfvpib/rNiD637xeevjO2l3Z5loZmuaRi0L0YE5LfijwVY96oyVn0DFD3o/teAok7nfobMG1THvvcHh/BP6g==", + "node_modules/import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==", "dev": true, - "dependencies": { - "cli-truncate": "^4.0.0", - "colorette": "^2.0.20", - "eventemitter3": "^5.0.1", - "log-update": "^6.0.0", - "rfdc": "^1.3.1", - "wrap-ansi": "^9.0.0" - }, "engines": { - "node": ">=18.0.0" + "node": ">=4" } }, - "node_modules/listr2/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==", + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, "engines": { - "node": ">=12" + "node": ">=8" }, "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/listr2/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "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": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=0.8.19" } }, - "node_modules/listr2/node_modules/emoji-regex": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", - "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", - "dev": true + "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==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } }, - "node_modules/listr2/node_modules/eventemitter3": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true }, - "node_modules/listr2/node_modules/string-width": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", - "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", - "dev": true, + "node_modules/inquirer": { + "version": "8.2.6", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", + "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^6.0.1" }, "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=12.0.0" } }, - "node_modules/listr2/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, + "node_modules/inquirer/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "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/listr2/node_modules/wrap-ansi": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", - "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", - "dev": true, + "node_modules/inquirer/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==", "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" + "restore-cursor": "^3.1.0" }, "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "node": ">=8" } }, - "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==", + "node_modules/inquirer/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==", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, "engines": { - "node": ">=6.11.5" + "node": ">=8" } }, - "node_modules/loader-utils": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", - "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", + "node_modules/inquirer/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==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, "engines": { - "node": ">= 12.13.0" + "node": ">=8" } }, - "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/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": { - "p-locate": "^4.1.0" + "es-errors": "^1.3.0", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" }, "engines": { - "node": ">=8" + "node": ">= 0.4" } }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "node_modules/lodash._reinterpolate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==" - }, - "node_modules/lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", - "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.flow": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/lodash.flow/-/lodash.flow-3.5.0.tgz", - "integrity": "sha512-ff3BX/tSioo+XojX4MOsOMhJw0nZoUEF011LX8g8d3gvjVbxd89cCio4BCXronjxcTUIJUoqKEUA+n4CqvvRPw==" - }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==" - }, - "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==" - }, - "node_modules/lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==" - }, - "node_modules/lodash.template": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", - "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", - "dependencies": { - "lodash._reinterpolate": "^3.0.0", - "lodash.templatesettings": "^4.0.0" + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "engines": { + "node": ">=12" } }, - "node_modules/lodash.templatesettings": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", - "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", "dependencies": { - "lodash._reinterpolate": "^3.0.0" + "loose-envify": "^1.0.0" } }, - "node_modules/lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" - }, - "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==", + "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": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/log-symbols/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "has-tostringtag": "^1.0.0" }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/log-update": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.0.0.tgz", - "integrity": "sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw==", + "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": { - "ansi-escapes": "^6.2.0", - "cli-cursor": "^4.0.0", - "slice-ansi": "^7.0.0", - "strip-ansi": "^7.1.0", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=18" + "has-bigints": "^1.0.1" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/log-update/node_modules/ansi-escapes": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.1.tgz", - "integrity": "sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==", + "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==", + "devOptional": 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": ">=14.16" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/log-update/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==", + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "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": ">=12" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/log-update/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "node_modules/is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", "dev": true, - "engines": { - "node": ">=12" + "dependencies": { + "ci-info": "^2.0.0" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "bin": { + "is-ci": "bin.js" } }, - "node_modules/log-update/node_modules/emoji-regex": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", - "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "node_modules/is-ci/node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", "dev": true }, - "node_modules/log-update/node_modules/is-fullwidth-code-point": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz", - "integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==", - "dev": true, + "node_modules/is-core-module": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", "dependencies": { - "get-east-asian-width": "^1.0.0" + "hasown": "^2.0.2" }, "engines": { - "node": ">=18" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/log-update/node_modules/slice-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz", - "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==", + "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": { - "ansi-styles": "^6.2.1", - "is-fullwidth-code-point": "^5.0.0" + "is-typed-array": "^1.1.13" }, "engines": { - "node": ">=18" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/log-update/node_modules/string-width": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", - "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", + "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": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" + "has-tostringtag": "^1.0.0" }, "engines": { - "node": ">=18" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/log-update/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/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" + "bin": { + "is-docker": "cli.js" }, "engines": { - "node": ">=12" + "node": ">=8" }, "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/log-update/node_modules/wrap-ansi": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", - "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", - "dev": true, + "node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" + "is-plain-object": "^2.0.4" }, "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "node": ">=0.10.0" } }, - "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/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "devOptional": true, + "engines": { + "node": ">=0.10.0" } }, - "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==", + "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": { - "tslib": "^2.0.3" + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "dev": true, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "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/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "engines": { + "node": ">=6" } }, - "node_modules/lunr": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", - "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", - "peer": true - }, - "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==", + "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, - "bin": { - "lz-string": "bin/bin.js" + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/magic-string": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", - "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "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==", + "devOptional": true, "dependencies": { - "sourcemap-codec": "^1.4.8" + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "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==", + "node_modules/is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "dev": true, "dependencies": { - "semver": "^6.0.0" + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" }, "engines": { - "node": ">=8" + "node": ">=10" }, "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==", - "bin": { - "semver": "bin/semver.js" + "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==", + "engines": { + "node": ">=8" } }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dependencies": { - "tmpl": "1.0.5" + "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/map-obj": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", - "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", - "optional": true, - "peer": true, + "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-npm": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", + "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==", + "dev": true, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/markdown-link": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/markdown-link/-/markdown-link-0.1.1.tgz", - "integrity": "sha512-TurLymbyLyo+kAUUAV9ggR9EPcDjP/ctlv9QAFiqUH7c+t6FlsbivPo9OKTU8xdOx9oNd2drW/Fi5RRElQbUqA==", + "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==", + "devOptional": true, "engines": { - "node": ">=0.10.0" + "node": ">=0.12.0" } }, - "node_modules/markdown-toc": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/markdown-toc/-/markdown-toc-1.2.0.tgz", - "integrity": "sha512-eOsq7EGd3asV0oBfmyqngeEIhrbkc7XVP63OwcJBIhH2EpG2PzFcbZdhy1jutXSlRBBVMNXHvMtSr5LAxSUvUg==", + "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": { - "concat-stream": "^1.5.2", - "diacritics-map": "^0.1.0", - "gray-matter": "^2.1.0", - "lazy-cache": "^2.0.2", - "list-item": "^1.1.1", - "markdown-link": "^0.1.1", - "minimist": "^1.2.0", - "mixin-deep": "^1.1.3", - "object.pick": "^1.2.0", - "remarkable": "^1.7.1", - "repeat-string": "^1.6.1", - "strip-color": "^0.1.0" - }, - "bin": { - "markdown-toc": "cli.js" + "has-tostringtag": "^1.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/marked": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", - "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", - "peer": true, - "bin": { - "marked": "bin/marked.js" - }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true, "engines": { - "node": ">= 12" + "node": ">=8" } }, - "node_modules/math-random": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", - "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==" - }, - "node_modules/mdn-data": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", - "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==" - }, - "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==", + "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": ">= 0.6" + "node": ">=8" } }, - "node_modules/memfs": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", - "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "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==", "dependencies": { - "fs-monkey": "^1.0.4" + "isobject": "^3.0.1" }, "engines": { - "node": ">= 4.0.0" + "node": ">=0.10.0" } }, - "node_modules/meow": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz", - "integrity": "sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==", - "optional": true, - "peer": true, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, + "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": { - "@types/minimist": "^1.2.0", - "camelcase-keys": "^6.2.2", - "decamelize": "^1.2.0", - "decamelize-keys": "^1.1.0", - "hard-rejection": "^2.1.0", - "minimist-options": "4.1.0", - "normalize-package-data": "^3.0.0", - "read-pkg-up": "^7.0.1", - "redent": "^3.0.0", - "trim-newlines": "^3.0.0", - "type-fest": "^0.18.0", - "yargs-parser": "^20.2.3" + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/meow/node_modules/type-fest": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", - "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", - "optional": true, - "peer": true, + "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": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/merge": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/merge/-/merge-2.1.1.tgz", - "integrity": "sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w==", - "dev": true - }, - "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==" - }, - "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==" - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "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": ">= 8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "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": ">= 0.6" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "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": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" + "has-tostringtag": "^1.0.0" }, "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==", - "bin": { - "mime": "cli.js" + "node": ">= 0.4" }, - "engines": { - "node": ">=4" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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==", + "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.6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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==", + "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": { - "mime-db": "1.52.0" + "which-typed-array": "^1.1.14" }, "engines": { - "node": ">= 0.6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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==", + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true + }, + "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==", "engines": { - "node": ">=6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "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": ">=4" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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==", - "devOptional": true, - "engines": { - "node": ">=4" + "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/mini-css-extract-plugin": { - "version": "2.7.6", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.6.tgz", - "integrity": "sha512-Qk7HcgaPkGG6eD77mLvZS1nmxlao3j+9PkrT9Uc7HAE1id3F41+DdBRYRYkbyfNRGzm8/YWtzhw7nVPmwhqTQw==", + "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": { - "schema-utils": "^4.0.0" + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/mini-css-extract-plugin/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==", - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/mini-css-extract-plugin/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==", + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" + "is-docker": "^2.0.0" }, "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "node": ">=8" } }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + "node_modules/is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", + "dev": true }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, + "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/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==", "engines": { - "node": "*" + "node": ">=0.10.0" } }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true, + "engines": { + "node": ">=8" } }, - "node_modules/minimist-options": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", - "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", - "optional": true, - "peer": true, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, "dependencies": { - "arrify": "^1.0.1", - "is-plain-obj": "^1.1.0", - "kind-of": "^6.0.3" + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" }, "engines": { - "node": ">= 6" + "node": ">=8" } }, - "node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "optional": true, - "peer": true, + "node_modules/istanbul-lib-instrument/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/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, "dependencies": { - "yallist": "^4.0.0" + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" }, "engines": { "node": ">=8" } }, - "node_modules/minipass-collect": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", - "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", - "optional": true, - "peer": true, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, "dependencies": { - "minipass": "^3.0.0" + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" }, "engines": { - "node": ">= 8" + "node": ">=10" } }, - "node_modules/minipass-flush": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "optional": true, - "peer": true, - "dependencies": { - "minipass": "^3.0.0" - }, + "node_modules/istanbul-lib-source-maps/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": ">= 8" + "node": ">=0.10.0" } }, - "node_modules/minipass-pipeline": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "optional": true, - "peer": true, + "node_modules/istanbul-reports": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "dev": true, "dependencies": { - "minipass": "^3.0.0" + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/minipass-sized": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "optional": true, - "peer": true, + "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": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", + "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", + "dev": true, "dependencies": { - "minipass": "^3.0.0" + "@jest/core": "^27.5.1", + "import-local": "^3.0.2", + "jest-cli": "^27.5.1" + }, + "bin": { + "jest": "bin/jest.js" }, "engines": { - "node": ">=8" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/minipass/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true, - "peer": true - }, - "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "optional": true, - "peer": true, + "node_modules/jest-changed-files": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.5.1.tgz", + "integrity": "sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==", + "dev": true, "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" + "@jest/types": "^27.5.1", + "execa": "^5.0.0", + "throat": "^6.0.1" }, "engines": { - "node": ">= 8" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "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==", - "optional": true, - "peer": true - }, - "node_modules/mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "node_modules/jest-circus": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.5.1.tgz", + "integrity": "sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==", + "dev": true, "dependencies": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3", + "throat": "^6.0.1" }, "engines": { - "node": ">=0.10.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "optional": true, - "peer": true, - "bin": { - "mkdirp": "bin/cmd.js" + "node_modules/jest-circus/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/mrmime": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", - "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==", + "node_modules/jest-circus/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" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "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/multicast-dns": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", - "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", - "dependencies": { - "dns-packet": "^5.2.2", - "thunky": "^1.0.2" + "node_modules/jest-circus/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" }, - "bin": { - "multicast-dns": "cli.js" + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" + "node_modules/jest-circus/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/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "node_modules/jest-cli": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", + "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", + "dev": true, "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "node_modules/nan": { - "version": "2.17.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", - "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==", - "optional": true, - "peer": true - }, - "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], + "@jest/core": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "prompts": "^2.0.1", + "yargs": "^16.2.0" + }, "bin": { - "nanoid": "bin/nanoid.cjs" + "jest": "bin/jest.js" }, "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==" - }, - "node_modules/natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==" - }, - "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==", - "engines": { - "node": ">= 0.6" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "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==" - }, - "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==", + "node_modules/jest-cli/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": { - "lower-case": "^2.0.2", - "tslib": "^2.0.3" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "node_modules/jest-config": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", + "integrity": "sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==", + "dev": true, "dependencies": { - "whatwg-url": "^5.0.0" + "@babel/core": "^7.8.0", + "@jest/test-sequencer": "^27.5.1", + "@jest/types": "^27.5.1", + "babel-jest": "^27.5.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "graceful-fs": "^4.2.9", + "jest-circus": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-jasmine2": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" }, "engines": { - "node": "4.x || >=6.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" }, "peerDependencies": { - "encoding": "^0.1.0" + "ts-node": ">=9.0.0" }, "peerDependenciesMeta": { - "encoding": { + "ts-node": { "optional": true } } }, - "node_modules/node-fetch/node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "node_modules/node-fetch/node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "node_modules/node-fetch/node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "node_modules/jest-config/node_modules/babel-jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", + "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", + "dev": true, "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" } }, - "node_modules/node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "node_modules/jest-config/node_modules/babel-plugin-jest-hoist": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz", + "integrity": "sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==", + "dev": true, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" + }, "engines": { - "node": ">= 6.13.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/node-gyp": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", - "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", - "optional": true, - "peer": true, + "node_modules/jest-config/node_modules/babel-preset-jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz", + "integrity": "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==", + "dev": true, "dependencies": { - "env-paths": "^2.2.0", - "glob": "^7.1.4", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^9.1.0", - "nopt": "^5.0.0", - "npmlog": "^6.0.0", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.2", - "which": "^2.0.2" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" + "babel-plugin-jest-hoist": "^27.5.1", + "babel-preset-current-node-syntax": "^1.0.0" }, "engines": { - "node": ">= 10.12.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/node-gyp/node_modules/@npmcli/fs": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", - "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", - "optional": true, - "peer": true, + "node_modules/jest-config/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": { - "@gar/promisify": "^1.0.1", - "semver": "^7.3.5" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/node-gyp/node_modules/@npmcli/move-file": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", - "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", - "deprecated": "This functionality has been moved to @npmcli/fs", - "optional": true, - "peer": true, + "node_modules/jest-config/node_modules/jest-environment-node": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.5.1.tgz", + "integrity": "sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==", + "dev": true, "dependencies": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" }, "engines": { - "node": ">=10" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/node-gyp/node_modules/cacache": { - "version": "15.3.0", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", - "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", - "optional": true, - "peer": true, + "node_modules/jest-config/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": { - "@npmcli/fs": "^1.0.0", - "@npmcli/move-file": "^1.0.1", - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", - "infer-owner": "^1.0.4", - "lru-cache": "^6.0.0", - "minipass": "^3.1.1", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^1.0.3", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^8.0.1", - "tar": "^6.0.2", - "unique-filename": "^1.1.1" + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" }, "engines": { - "node": ">= 10" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/node-gyp/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "optional": true, - "peer": true, - "dependencies": { - "yallist": "^4.0.0" - }, + "node_modules/jest-config/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/node-gyp/node_modules/make-fetch-happen": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", - "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", - "optional": true, - "peer": true, + "node_modules/jest-config/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/jest-diff": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", + "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", + "dev": true, "dependencies": { - "agentkeepalive": "^4.1.3", - "cacache": "^15.2.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^6.0.0", - "minipass": "^3.1.3", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^1.3.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.2", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^6.0.0", - "ssri": "^8.0.0" + "chalk": "^4.0.0", + "diff-sequences": "^26.6.2", + "jest-get-type": "^26.3.0", + "pretty-format": "^26.6.2" }, "engines": { - "node": ">= 10" + "node": ">= 10.14.2" } }, - "node_modules/node-gyp/node_modules/minipass-fetch": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", - "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", - "optional": true, - "peer": true, + "node_modules/jest-diff/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": { - "minipass": "^3.1.0", - "minipass-sized": "^1.0.3", - "minizlib": "^2.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=8" + "node": ">=10" }, - "optionalDependencies": { - "encoding": "^0.1.12" + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/node-gyp/node_modules/socks-proxy-agent": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", - "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", - "optional": true, - "peer": true, - "dependencies": { - "agent-base": "^6.0.2", - "debug": "^4.3.3", - "socks": "^2.6.2" - }, + "node_modules/jest-diff/node_modules/jest-get-type": { + "version": "26.3.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", + "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", + "dev": true, "engines": { - "node": ">= 10" + "node": ">= 10.14.2" } }, - "node_modules/node-gyp/node_modules/ssri": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", - "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", - "optional": true, - "peer": true, + "node_modules/jest-docblock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz", + "integrity": "sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==", + "dev": true, "dependencies": { - "minipass": "^3.1.1" + "detect-newline": "^3.0.0" }, "engines": { - "node": ">= 8" - } - }, - "node_modules/node-gyp/node_modules/unique-filename": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", - "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", - "optional": true, - "peer": true, - "dependencies": { - "unique-slug": "^2.0.0" - } - }, - "node_modules/node-gyp/node_modules/unique-slug": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", - "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", - "optional": true, - "peer": true, - "dependencies": { - "imurmurhash": "^0.1.4" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/node-gyp/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true, - "peer": true - }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==" - }, - "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/node-sass": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-7.0.3.tgz", - "integrity": "sha512-8MIlsY/4dXUkJDYht9pIWBhMil3uHmE8b/AdJPjmFn1nBx9X9BASzfzmsCy0uCCb8eqI3SYYzVPDswWqSx7gjw==", - "hasInstallScript": true, - "optional": true, - "peer": true, - "dependencies": { - "async-foreach": "^0.1.3", - "chalk": "^4.1.2", - "cross-spawn": "^7.0.3", - "gaze": "^1.0.0", - "get-stdin": "^4.0.1", - "glob": "^7.0.3", - "lodash": "^4.17.15", - "meow": "^9.0.0", - "nan": "^2.13.2", - "node-gyp": "^8.4.1", - "npmlog": "^5.0.0", - "request": "^2.88.0", - "sass-graph": "^4.0.1", - "stdout-stream": "^1.4.0", - "true-case-path": "^1.0.2" - }, - "bin": { - "node-sass": "bin/node-sass" - }, + "node_modules/jest-docblock/node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, "engines": { - "node": ">=12" + "node": ">=8" } }, - "node_modules/node-sass/node_modules/are-we-there-yet": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", - "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", - "optional": true, - "peer": true, + "node_modules/jest-each": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.5.1.tgz", + "integrity": "sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==", + "dev": true, "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1" }, "engines": { - "node": ">=10" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/node-sass/node_modules/chalk": { + "node_modules/jest-each/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "optional": true, - "peer": true, + "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -17690,427 +15529,439 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/node-sass/node_modules/gauge": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", - "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", - "optional": true, - "peer": true, + "node_modules/jest-each/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": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.2", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.1", - "object-assign": "^4.1.1", - "signal-exit": "^3.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.2" + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" }, "engines": { - "node": ">=10" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/node-sass/node_modules/npmlog": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", - "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", - "optional": true, - "peer": true, - "dependencies": { - "are-we-there-yet": "^2.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^3.0.0", - "set-blocking": "^2.0.0" + "node_modules/jest-each/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/nopt": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", - "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "optional": true, - "peer": true, + "node_modules/jest-each/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/jest-environment-jsdom": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz", + "integrity": "sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==", + "dev": true, "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1", + "jsdom": "^16.6.0" }, "engines": { - "node": ">=6" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/normalize-package-data": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", - "optional": true, - "peer": true, - "dependencies": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" - }, + "node_modules/jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "dev": true, "engines": { - "node": ">=10" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "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==", + "node_modules/jest-haste-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", + "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "micromatch": "^4.0.4", + "walker": "^1.0.7" + }, "engines": { - "node": ">=0.10.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" } }, - "node_modules/normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "node_modules/jest-jasmine2": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz", + "integrity": "sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==", + "dev": true, + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "throat": "^6.0.1" + }, "engines": { - "node": ">=0.10.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "node_modules/jest-jasmine2/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/sponsors/sindresorhus" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "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==", + "node_modules/jest-jasmine2/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": { - "path-key": "^3.0.0" + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" }, "engines": { - "node": ">=8" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/npmlog": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", - "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", - "optional": true, - "peer": true, - "dependencies": { - "are-we-there-yet": "^3.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^4.0.3", - "set-blocking": "^2.0.0" - }, + "node_modules/jest-jasmine2/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": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "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" + "node": ">=10" }, "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/nwsapi": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", - "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==" - }, - "node_modules/oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "optional": true, - "peer": true, - "engines": { - "node": "*" - } + "node_modules/jest-jasmine2/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/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==", + "node_modules/jest-leak-detector": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz", + "integrity": "sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==", + "dev": true, + "dependencies": { + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, "engines": { - "node": ">=0.10.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/object-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "node_modules/jest-leak-detector/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": ">= 6" - } - }, - "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "node": ">=10" + }, "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==", - "engines": { - "node": ">= 0.4" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "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==", + "node_modules/jest-leak-detector/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": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "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==", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, + "node_modules/jest-leak-detector/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/jest-localstorage-mock": { + "version": "2.4.26", + "resolved": "https://registry.npmjs.org/jest-localstorage-mock/-/jest-localstorage-mock-2.4.26.tgz", + "integrity": "sha512-owAJrYnjulVlMIXOYQIPRCCn3MmqI3GzgfZCXdD3/pmwrIvFMXcKVWZ+aMc44IzaASapg0Z4SEFxR+v5qxDA2w==", + "dev": true, "engines": { - "node": ">= 0.4" + "node": ">=6.16.0" } }, - "node_modules/object.fromentries": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", - "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", + "node_modules/jest-location-mock": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jest-location-mock/-/jest-location-mock-2.0.0.tgz", + "integrity": "sha512-loakfclgY/y65/2i4s0fcdlZY3hRPfwNnmzRsGFQYQryiaow2DEIGTLXIPI8cAO1Is36xsVLVkIzgvhQ+FXHdw==", + "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "@jedmao/location": "^3.0.0", + "jest-diff": "^29.6.4" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^16.10.0 || >=18.0.0" } }, - "node_modules/object.getownpropertydescriptors": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.6.tgz", - "integrity": "sha512-lq+61g26E/BgHv0ZTFgRvi7NMEPuAxLkFU7rukXjc/AlwH4Am5xXVnIXy3un1bg/JPbXHrixRkK1itUzzPiIjQ==", + "node_modules/jest-location-mock/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": { - "array.prototype.reduce": "^1.0.5", - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.21.2", - "safe-array-concat": "^1.0.0" + "@sinclair/typebox": "^0.27.8" }, "engines": { - "node": ">= 0.8" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/object.groupby": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.1.tgz", - "integrity": "sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1" - } + "node_modules/jest-location-mock/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/object.hasown": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.4.tgz", - "integrity": "sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==", + "node_modules/jest-location-mock/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": { - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", - "dependencies": { - "isobject": "^3.0.1" - }, + "node_modules/jest-location-mock/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": ">=0.10.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/object.values": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", - "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", + "node_modules/jest-location-mock/node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/obuf": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" + "node_modules/jest-location-mock/node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } }, - "node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "node_modules/jest-location-mock/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": { - "ee-first": "1.1.1" + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": ">= 0.8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "node_modules/jest-location-mock/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": ">= 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==", - "dependencies": { - "wrappy": "1" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "node_modules/jest-matcher-utils": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", + "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "dev": true, "dependencies": { - "mimic-fn": "^2.1.0" + "chalk": "^4.0.0", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" }, "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/open": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", - "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "node_modules/jest-matcher-utils/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": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=12" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/optimism": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/optimism/-/optimism-0.16.2.tgz", - "integrity": "sha512-zWNbgWj+3vLEjZNIh/okkY2EUfX+vB9TJopzIZwT1xxaMqC5hRLLraePod4c5n4He08xuXNH+zhKFFCu390wiQ==", - "dependencies": { - "@wry/context": "^0.7.0", - "@wry/trie": "^0.3.0" + "node_modules/jest-matcher-utils/node_modules/diff-sequences": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/optimism/node_modules/@wry/trie": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@wry/trie/-/trie-0.3.2.tgz", - "integrity": "sha512-yRTyhWSls2OY/pYLfwff867r8ekooZ4UI+/gxot5Wj8EFwSf2rG+n+Mo/6LoLQm1TKA4GRj2+LCpbfS937dClQ==", + "node_modules/jest-matcher-utils/node_modules/jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "dev": true, "dependencies": { - "tslib": "^2.3.0" + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" }, "engines": { - "node": ">=8" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "node_modules/jest-matcher-utils/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": { - "@aashutoshrathi/word-wrap": "^1.2.3", - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" }, "engines": { - "node": ">= 0.8.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.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==", - "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" - }, + "node_modules/jest-matcher-utils/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/sponsors/sindresorhus" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/ora/node_modules/chalk": { + "node_modules/jest-matcher-utils/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/jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-message-util/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" @@ -18122,80 +15973,104 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/ora/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==", + "node_modules/jest-message-util/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": { - "restore-cursor": "^3.1.0" + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" }, "engines": { - "node": ">=8" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/ora/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==", - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, + "node_modules/jest-message-util/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": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "node_modules/jest-message-util/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/jest-mock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*" + }, "engines": { - "node": ">=0.10.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/p-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", "dev": true, "engines": { "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } } }, - "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-preview": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/jest-preview/-/jest-preview-0.3.1.tgz", + "integrity": "sha512-gRR4shnXFSh8tdNaIncJC98d1zXD7w7LA52HQC0bu0DsPb+FXVEg+NQh9GTbO+n6/SCgcZNQAVt4MeCfsIkBPA==", + "dev": true, + "hasInstallScript": true, "dependencies": { - "p-try": "^2.0.0" + "@svgr/core": "^6.2.1", + "camelcase": "^6.3.0", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "commander": "^9.2.0", + "connect": "^3.7.0", + "find-node-modules": "^2.1.3", + "open": "^8.4.0", + "postcss-import": "^14.1.0", + "postcss-load-config": "^4.0.1", + "sirv": "^2.0.2", + "slash": "^3.0.0", + "string-hash": "^1.1.3", + "update-notifier": "^5.1.0", + "ws": "^8.5.0" }, - "engines": { - "node": ">=6" + "bin": { + "jest-preview": "cli/index.js" }, "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==", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" + "type": "opencollective", + "url": "https://opencollective.com/jest-preview" } }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "optional": true, - "peer": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, + "node_modules/jest-preview/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, "engines": { "node": ">=10" }, @@ -18203,2169 +16078,2111 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-retry": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", - "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "node_modules/jest-preview/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": { - "@types/retry": "0.12.0", - "retry": "^0.13.1" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=8" - } - }, - "node_modules/p-retry/node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "engines": { - "node": ">= 4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "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==", + "node_modules/jest-regex-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", + "dev": true, "engines": { - "node": ">=6" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/package-json": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", - "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "node_modules/jest-resolve": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz", + "integrity": "sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==", "dev": true, "dependencies": { - "got": "^9.6.0", - "registry-auth-token": "^4.0.0", - "registry-url": "^5.0.0", - "semver": "^6.2.0" + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^3.0.0" }, "engines": { - "node": ">=8" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/package-json/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "node_modules/jest-resolve-dependencies": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz", + "integrity": "sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==", "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" - }, - "node_modules/param-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", - "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", - "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" + "@jest/types": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-snapshot": "^27.5.1" }, "engines": { - "node": ">=6" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "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==", + "node_modules/jest-resolve/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": { - "@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" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", + "node_modules/jest-runner": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.5.1.tgz", + "integrity": "sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==", "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/parse-srcset": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz", - "integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==" - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "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==", "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "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==", - "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==", - "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==", + "@jest/console": "^27.5.1", + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-leak-detector": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "source-map-support": "^0.5.6", + "throat": "^6.0.1" + }, "engines": { - "node": ">=8" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "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-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "node_modules/jest-runner/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": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "engines": { - "node": ">=8.6" + "node_modules/jest-runner/node_modules/jest-environment-node": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.5.1.tgz", + "integrity": "sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==", + "dev": true, + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/pidtree": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", - "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "node_modules/jest-runtime": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.5.1.tgz", + "integrity": "sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==", "dev": true, - "bin": { - "pidtree": "bin/pidtree.js" + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/globals": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "execa": "^5.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" }, "engines": { - "node": ">=0.10" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "node_modules/jest-runtime/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": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "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==", + "node_modules/jest-serializer": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", + "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", + "dev": true, + "dependencies": { + "@types/node": "*", + "graceful-fs": "^4.2.9" + }, "engines": { - "node": ">= 6" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "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==", + "node_modules/jest-snapshot": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.5.1.tgz", + "integrity": "sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==", + "dev": true, "dependencies": { - "find-up": "^4.0.0" + "@babel/core": "^7.7.2", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.0.0", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__traverse": "^7.0.4", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", + "natural-compare": "^1.4.0", + "pretty-format": "^27.5.1", + "semver": "^7.3.2" }, "engines": { - "node": ">=8" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/pkg-up": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", - "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "node_modules/jest-snapshot/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": { - "find-up": "^3.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/pkg-up/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==", - "dependencies": { - "locate-path": "^3.0.0" - }, + "node_modules/jest-snapshot/node_modules/diff-sequences": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "dev": true, "engines": { - "node": ">=6" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/pkg-up/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==", + "node_modules/jest-snapshot/node_modules/jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "dev": true, "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" }, "engines": { - "node": ">=6" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/pkg-up/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==", + "node_modules/jest-snapshot/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": { - "p-limit": "^2.0.0" + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" }, "engines": { - "node": ">=6" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/pkg-up/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==", + "node_modules/jest-snapshot/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": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "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==", - "engines": { - "node": ">= 0.4" - } + "node_modules/jest-snapshot/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/postcss": { - "version": "8.4.35", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", - "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", - "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" - } - ], + "node_modules/jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "dev": true, "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" }, "engines": { - "node": "^10 || ^12 || >=14" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/postcss-attribute-case-insensitive": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-5.0.2.tgz", - "integrity": "sha512-XIidXV8fDr0kKt28vqki84fRK8VW8eTuIa4PChv2MqKuT6C9UjmSKzen6KaWhWEoYvwxFCa7n/tC1SZ3tyq4SQ==", + "node_modules/jest-util/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": { - "postcss-selector-parser": "^6.0.10" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": "^12 || ^14 || >=16" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/postcss-browser-comments": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-browser-comments/-/postcss-browser-comments-4.0.0.tgz", - "integrity": "sha512-X9X9/WN3KIvY9+hNERUqX9gncsgBA25XaeR+jshHz2j8+sYyHktHw1JdKuMjeLpGktXidqDhA7b/qm1mrBDmgg==", - "engines": { - "node": ">=8" + "node_modules/jest-validate": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", + "integrity": "sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "leven": "^3.1.0", + "pretty-format": "^27.5.1" }, - "peerDependencies": { - "browserslist": ">=4", - "postcss": ">=8" + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/postcss-calc": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz", - "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==", - "dependencies": { - "postcss-selector-parser": "^6.0.9", - "postcss-value-parser": "^4.2.0" + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" }, - "peerDependencies": { - "postcss": "^8.2.2" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/postcss-clamp": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-clamp/-/postcss-clamp-4.1.0.tgz", - "integrity": "sha512-ry4b1Llo/9zz+PKC+030KUnPITTJAHeOwjfAyyB60eT0AorGLdzp52s31OsPRHRf8NchkgFoG2y6fCfn1IV1Ow==", + "node_modules/jest-validate/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": { - "postcss-value-parser": "^4.2.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=7.6.0" + "node": ">=10" }, - "peerDependencies": { - "postcss": "^8.4.6" + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/postcss-color-functional-notation": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-4.2.4.tgz", - "integrity": "sha512-2yrTAUZUab9s6CpxkxC4rVgFEVaR6/2Pipvi6qcgvnYiVqZcbDHEoBDhrXzyb7Efh2CCfHQNtcqWcIruDTIUeg==", + "node_modules/jest-validate/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": { - "postcss-value-parser": "^4.2.0" + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" }, "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/postcss-color-hex-alpha": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-8.0.4.tgz", - "integrity": "sha512-nLo2DCRC9eE4w2JmuKgVA3fGL3d01kGq752pVALF68qpGLmx2Qrk91QTKkdUqqp45T1K1XV8IhQpcu1hoAQflQ==", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, + "node_modules/jest-validate/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": "^12 || ^14 || >=16" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.4" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/postcss-color-rebeccapurple": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-7.1.1.tgz", - "integrity": "sha512-pGxkuVEInwLHgkNxUc4sdg4g3py7zUeCQ9sMfwyHAT+Ezk8a4OaaVZ8lIY5+oNqA/BXXgLyXv0+5wHP68R79hg==", + "node_modules/jest-validate/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/jest-watcher": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.5.1.tgz", + "integrity": "sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==", + "dev": true, "dependencies": { - "postcss-value-parser": "^4.2.0" + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "jest-util": "^27.5.1", + "string-length": "^4.0.1" }, "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/postcss-colormin": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.1.tgz", - "integrity": "sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==", + "node_modules/jest-watcher/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": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0", - "colord": "^2.9.1", - "postcss-value-parser": "^4.2.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": ">=10" }, - "peerDependencies": { - "postcss": "^8.2.15" + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/postcss-convert-values": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz", - "integrity": "sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==", + "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": { - "browserslist": "^4.21.4", - "postcss-value-parser": "^4.2.0" + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" + "node": ">= 10.13.0" } }, - "node_modules/postcss-custom-media": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-8.0.2.tgz", - "integrity": "sha512-7yi25vDAoHAkbhAzX9dHx2yc6ntS4jQvejrNcC+csQJAXjj15e7VcWfMgLqBNAbOvqi5uIa9huOVwdHbf+sKqg==", + "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": { - "postcss-value-parser": "^4.2.0" + "has-flag": "^4.0.0" }, "engines": { - "node": "^12 || ^14 || >=16" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.3" + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/postcss-custom-properties": { - "version": "12.1.11", - "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.11.tgz", - "integrity": "sha512-0IDJYhgU8xDv1KY6+VgUwuQkVtmYzRwu+dMjnmdMafXYv86SWqfxkc7qdDvWS38vsjaEtv8e0vGOUQrAiMBLpQ==", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, + "node_modules/jju": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", + "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", + "dev": true + }, + "node_modules/js-cookie": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", + "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "node": ">=14" } }, - "node_modules/postcss-custom-selectors": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-6.0.3.tgz", - "integrity": "sha512-fgVkmyiWDwmD3JbpCmB45SvvlCD6z9CG6Ie6Iere22W5aHea6oWa7EM2bpnv2Fj3I94L3VbtvX9KqwSi5aFzSg==", + "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": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dependencies": { - "postcss-selector-parser": "^6.0.4" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "argparse": "^1.0.7", + "esprima": "^4.0.0" }, - "peerDependencies": { - "postcss": "^8.3" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/postcss-dir-pseudo-class": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-6.0.5.tgz", - "integrity": "sha512-eqn4m70P031PF7ZQIvSgy9RSJ5uI2171O/OO/zcRNYpJbvaeKFUlar1aJ7rmgiQtbm0FSPsRewjpdS0Oew7MPA==", + "node_modules/jsdom": { + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", + "dev": true, "dependencies": { - "postcss-selector-parser": "^6.0.10" + "abab": "^2.0.5", + "acorn": "^8.2.4", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.3.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.1", + "domexception": "^2.0.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", + "html-encoding-sniffer": "^2.0.1", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.5.0", + "ws": "^7.4.6", + "xml-name-validator": "^3.0.0" }, "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "node": ">=10" }, "peerDependencies": { - "postcss": "^8.2" - } - }, - "node_modules/postcss-discard-comments": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz", - "integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==", - "engines": { - "node": "^10 || ^12 || >=14.0" + "canvas": "^2.5.0" }, - "peerDependencies": { - "postcss": "^8.2.15" + "peerDependenciesMeta": { + "canvas": { + "optional": true + } } }, - "node_modules/postcss-discard-duplicates": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz", - "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==", + "node_modules/jsdom/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, + "node_modules/jsdom/node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "dev": true, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": ">=8.3.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } } }, - "node_modules/postcss-discard-empty": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz", - "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==", - "engines": { - "node": "^10 || ^12 || >=14.0" + "node_modules/jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" }, - "peerDependencies": { - "postcss": "^8.2.15" + "engines": { + "node": ">=6" } }, - "node_modules/postcss-discard-overridden": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz", - "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==", - "engines": { - "node": "^10 || ^12 || >=14.0" + "node_modules/json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==", + "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": "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/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, + "peer": 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" }, - "peerDependencies": { - "postcss": "^8.2.15" + "engines": { + "node": ">=6" } }, - "node_modules/postcss-double-position-gradients": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-3.1.2.tgz", - "integrity": "sha512-GX+FuE/uBR6eskOK+4vkXgT6pDkexLokPaz/AbJna9s5Kzp/yl488pKPjhy0obB475ovfT1Wv8ho7U/cHNaRgQ==", + "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": { - "@csstools/postcss-progressive-custom-properties": "^1.1.0", - "postcss-value-parser": "^4.2.0" + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" }, "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "node": ">=4.0" } }, - "node_modules/postcss-env-function": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-4.0.6.tgz", - "integrity": "sha512-kpA6FsLra+NqcFnL81TnsU+Z7orGtDTxcOhl6pwXeEq1yFPpRMkCDpHhrz8CFQDr/Wfm0jLiNQ1OsGGPjlqPwA==", + "node_modules/keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "dev": true, "dependencies": { - "postcss-value-parser": "^4.2.0" - }, + "json-buffer": "3.0.0" + } + }, + "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==", "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" + "node": ">=0.10.0" } }, - "node_modules/postcss-flexbugs-fixes": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-5.0.2.tgz", - "integrity": "sha512-18f9voByak7bTktR2QgDveglpn9DTbBWPUzSOe9g0N4WR/2eSt6Vrcbf0hmspvMI6YWGywz6B9f7jzpFNJJgnQ==", - "peerDependencies": { - "postcss": "^8.1.4" + "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/postcss-focus-visible": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-6.0.4.tgz", - "integrity": "sha512-QcKuUU/dgNsstIK6HELFRT5Y3lbrMLEOwG+A4s5cA+fx3A3y/JTq3X9LaOj3OC3ALH0XqyrgQIgey/MIZ8Wczw==", + "node_modules/latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "dev": true, "dependencies": { - "postcss-selector-parser": "^6.0.9" + "package-json": "^6.3.0" }, "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" + "node": ">=8" } }, - "node_modules/postcss-focus-within": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-5.0.4.tgz", - "integrity": "sha512-vvjDN++C0mu8jz4af5d52CB184ogg/sSxAFS+oUJQq2SuCe7T5U2iIsVJtsCp2d6R4j0jr5+q3rPkBVZkXD9fQ==", + "node_modules/lazy-cache": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-2.0.2.tgz", + "integrity": "sha512-7vp2Acd2+Kz4XkzxGxaB1FWOi8KjWIWsgdfD5MCb86DWvlLqhRPM+d6Pro3iNEL5VT9mstz5hKAlcd+QR6H3aA==", "dependencies": { - "postcss-selector-parser": "^6.0.9" + "set-getter": "^0.1.0" }, "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/postcss-font-variant": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz", - "integrity": "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==", - "peerDependencies": { - "postcss": "^8.1.0" + "node": ">=0.10.0" } }, - "node_modules/postcss-gap-properties": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-3.0.5.tgz", - "integrity": "sha512-IuE6gKSdoUNcvkGIqdtjtcMtZIFyXZhmFd5RUlg97iVEvp1BZKV5ngsAjCjrVy+14uhGBQl9tzmi1Qwq4kqVOg==", + "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": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "node": ">=6" } }, - "node_modules/postcss-image-set-function": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-4.0.7.tgz", - "integrity": "sha512-9T2r9rsvYzm5ndsBE8WgtrMlIT7VbtTfE7b3BQnudUqnBcBo7L758oc+o+pdj/dUV0l5wjwSdjeOH2DZtfv8qw==", + "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, + "peer": true, "dependencies": { - "postcss-value-parser": "^4.2.0" + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" }, "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "node": ">= 0.8.0" } }, - "node_modules/postcss-import": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.1.0.tgz", - "integrity": "sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==", + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", "dev": true, - "dependencies": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - }, "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "postcss": "^8.0.0" + "node": ">=10" } }, - "node_modules/postcss-initial": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-4.0.1.tgz", - "integrity": "sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==", - "peerDependencies": { - "postcss": "^8.0.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/postcss-js": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", - "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", "dependencies": { - "camelcase-css": "^2.0.1" - }, - "engines": { - "node": "^12 || ^14 || >= 16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.4.21" + "uc.micro": "^2.0.0" } }, - "node_modules/postcss-lab-function": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-4.2.1.tgz", - "integrity": "sha512-xuXll4isR03CrQsmxyz92LJB2xX9n+pZJ5jE9JgcnmsCammLyKdlzrBin+25dy6wIjfhJpKBAN80gsTlCgRk2w==", + "node_modules/lint-staged": { + "version": "15.2.8", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.8.tgz", + "integrity": "sha512-PUWFf2zQzsd9EFU+kM1d7UP+AZDbKFKuj+9JNVTBkhUFhbg4MAt6WfyMMwBfM4lYqd4D2Jwac5iuTu9rVj4zCQ==", + "dev": true, "dependencies": { - "@csstools/postcss-progressive-custom-properties": "^1.1.0", - "postcss-value-parser": "^4.2.0" + "chalk": "~5.3.0", + "commander": "~12.1.0", + "debug": "~4.3.6", + "execa": "~8.0.1", + "lilconfig": "~3.1.2", + "listr2": "~8.2.4", + "micromatch": "~4.0.7", + "pidtree": "~0.6.0", + "string-argv": "~0.3.2", + "yaml": "~2.5.0" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" }, "engines": { - "node": "^12 || ^14 || >=16" + "node": ">=18.12.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "url": "https://opencollective.com/lint-staged" } }, - "node_modules/postcss-load-config": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz", - "integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==", - "dependencies": { - "lilconfig": "^2.0.5", - "yaml": "^2.1.1" - }, + "node_modules/lint-staged/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, "engines": { - "node": ">= 14" + "node": "^12.17.0 || ^14.13 || >=16.0.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": ">=8.0.9", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "postcss": { - "optional": true - }, - "ts-node": { - "optional": true - } + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/postcss-load-config/node_modules/yaml": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz", - "integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==", + "node_modules/lint-staged/node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "dev": true, "engines": { - "node": ">= 14" + "node": ">=18" } }, - "node_modules/postcss-loader": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-6.2.1.tgz", - "integrity": "sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==", + "node_modules/lint-staged/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": { - "cosmiconfig": "^7.0.0", - "klona": "^2.0.5", - "semver": "^7.3.5" + "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": ">= 12.13.0" + "node": ">=16.17" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "postcss": "^7.0.0 || ^8.0.1", - "webpack": "^5.0.0" + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/postcss-logical": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-5.0.4.tgz", - "integrity": "sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g==", + "node_modules/lint-staged/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": "^12 || ^14 || >=16" + "node": ">=16" }, - "peerDependencies": { - "postcss": "^8.4" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/postcss-media-minmax": { + "node_modules/lint-staged/node_modules/human-signals": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-5.0.0.tgz", - "integrity": "sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ==", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "postcss": "^8.1.0" + "node": ">=16.17.0" } }, - "node_modules/postcss-merge-longhand": { - "version": "5.1.7", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz", - "integrity": "sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==", - "dependencies": { - "postcss-value-parser": "^4.2.0", - "stylehacks": "^5.1.1" - }, + "node_modules/lint-staged/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": "^10 || ^12 || >=14.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, - "peerDependencies": { - "postcss": "^8.2.15" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/postcss-merge-rules": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz", - "integrity": "sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==", - "dependencies": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0", - "cssnano-utils": "^3.1.0", - "postcss-selector-parser": "^6.0.5" - }, + "node_modules/lint-staged/node_modules/lilconfig": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", + "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", + "dev": true, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": ">=14" }, - "peerDependencies": { - "postcss": "^8.2.15" + "funding": { + "url": "https://github.com/sponsors/antonk52" } }, - "node_modules/postcss-minify-font-values": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz", - "integrity": "sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, + "node_modules/lint-staged/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": "^10 || ^12 || >=14.0" + "node": ">=12" }, - "peerDependencies": { - "postcss": "^8.2.15" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/postcss-minify-gradients": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz", - "integrity": "sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==", + "node_modules/lint-staged/node_modules/npm-run-path": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.2.0.tgz", + "integrity": "sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==", + "dev": true, "dependencies": { - "colord": "^2.9.1", - "cssnano-utils": "^3.1.0", - "postcss-value-parser": "^4.2.0" + "path-key": "^4.0.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, - "peerDependencies": { - "postcss": "^8.2.15" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/postcss-minify-params": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz", - "integrity": "sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==", + "node_modules/lint-staged/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": { - "browserslist": "^4.21.4", - "cssnano-utils": "^3.1.0", - "postcss-value-parser": "^4.2.0" + "mimic-fn": "^4.0.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": ">=12" }, - "peerDependencies": { - "postcss": "^8.2.15" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/postcss-minify-selectors": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz", - "integrity": "sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==", - "dependencies": { - "postcss-selector-parser": "^6.0.5" - }, + "node_modules/lint-staged/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": "^10 || ^12 || >=14.0" + "node": ">=12" }, - "peerDependencies": { - "postcss": "^8.2.15" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/postcss-modules": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules/-/postcss-modules-6.0.0.tgz", - "integrity": "sha512-7DGfnlyi/ju82BRzTIjWS5C4Tafmzl3R79YP/PASiocj+aa6yYphHhhKUOEoXQToId5rgyFgJ88+ccOUydjBXQ==", + "node_modules/lint-staged/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, - "dependencies": { - "generic-names": "^4.0.0", - "icss-utils": "^5.1.0", - "lodash.camelcase": "^4.3.0", - "postcss-modules-extract-imports": "^3.0.0", - "postcss-modules-local-by-default": "^4.0.0", - "postcss-modules-scope": "^3.0.0", - "postcss-modules-values": "^4.0.0", - "string-hash": "^1.1.1" + "engines": { + "node": ">=14" }, - "peerDependencies": { - "postcss": "^8.0.0" + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/postcss-modules-extract-imports": { + "node_modules/lint-staged/node_modules/strip-final-newline": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", - "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, "engines": { - "node": "^10 || ^12 || >= 14" + "node": ">=12" }, - "peerDependencies": { - "postcss": "^8.1.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/postcss-modules-local-by-default": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz", - "integrity": "sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA==", - "dependencies": { - "icss-utils": "^5.0.0", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.1.0" + "node_modules/lint-staged/node_modules/yaml": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.0.tgz", + "integrity": "sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==", + "dev": true, + "bin": { + "yaml": "bin.mjs" }, "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" + "node": ">= 14" } }, - "node_modules/postcss-modules-scope": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", - "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "node_modules/list-item": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/list-item/-/list-item-1.1.1.tgz", + "integrity": "sha512-S3D0WZ4J6hyM8o5SNKWaMYB1ALSacPZ2nHGEuCjmHZ+dc03gFeNZoNDcqfcnO4vDhTZmNrqrpYZCdXsRh22bzw==", "dependencies": { - "postcss-selector-parser": "^6.0.4" + "expand-range": "^1.8.1", + "extend-shallow": "^2.0.1", + "is-number": "^2.1.0", + "repeat-string": "^1.5.2" }, "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" + "node": ">=0.10.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==", + "node_modules/list-item/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dependencies": { - "icss-utils": "^5.0.0" + "is-extendable": "^0.1.0" }, "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" + "node": ">=0.10.0" } }, - "node_modules/postcss-nested": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", - "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", - "dependencies": { - "postcss-selector-parser": "^6.0.11" - }, + "node_modules/list-item/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "engines": { - "node": ">=12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.2.14" + "node": ">=0.10.0" } }, - "node_modules/postcss-nesting": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-10.2.0.tgz", - "integrity": "sha512-EwMkYchxiDiKUhlJGzWsD9b2zvq/r2SSubcRrgP+jujMXFzqvANLt16lJANC+5uZ6hjI7lpRmI6O8JIl+8l1KA==", + "node_modules/list-item/node_modules/is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha512-QUzH43Gfb9+5yckcrSA0VBDwEtDUchrk4F6tfJZQuNzDJbEDB9cZNzSfXGQ1jqmdDY/kl41lUOWM9syA8z8jlg==", "dependencies": { - "@csstools/selector-specificity": "^2.0.0", - "postcss-selector-parser": "^6.0.10" + "kind-of": "^3.0.2" }, "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "node": ">=0.10.0" } }, - "node_modules/postcss-normalize": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize/-/postcss-normalize-10.0.1.tgz", - "integrity": "sha512-+5w18/rDev5mqERcG3W5GZNMJa1eoYYNGo8gB7tEwaos0ajk3ZXAI4mHGcNT47NE+ZnZD1pEpUOFLvltIwmeJA==", + "node_modules/list-item/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dependencies": { - "@csstools/normalize.css": "*", - "postcss-browser-comments": "^4", - "sanitize.css": "*" + "is-buffer": "^1.1.5" }, "engines": { - "node": ">= 12" - }, - "peerDependencies": { - "browserslist": ">= 4", - "postcss": ">= 8" + "node": ">=0.10.0" } }, - "node_modules/postcss-normalize-charset": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz", - "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==", - "engines": { - "node": "^10 || ^12 || >=14.0" + "node_modules/listr2": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.4.tgz", + "integrity": "sha512-opevsywziHd3zHCVQGAj8zu+Z3yHNkkoYhWIGnq54RrCVwLz0MozotJEDnKsIBLvkfLGN6BLOyAeRrYI0pKA4g==", + "dev": true, + "dependencies": { + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" }, - "peerDependencies": { - "postcss": "^8.2.15" + "engines": { + "node": ">=18.0.0" } }, - "node_modules/postcss-normalize-display-values": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz", - "integrity": "sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, + "node_modules/listr2/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": "^10 || ^12 || >=14.0" + "node": ">=12" }, - "peerDependencies": { - "postcss": "^8.2.15" + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/postcss-normalize-positions": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz", - "integrity": "sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, + "node_modules/listr2/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": ">=12" }, - "peerDependencies": { - "postcss": "^8.2.15" + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/postcss-normalize-repeat-style": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz", - "integrity": "sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==", + "node_modules/listr2/node_modules/emoji-regex": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "dev": true + }, + "node_modules/listr2/node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true + }, + "node_modules/listr2/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, "dependencies": { - "postcss-value-parser": "^4.2.0" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": ">=18" }, - "peerDependencies": { - "postcss": "^8.2.15" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/postcss-normalize-string": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz", - "integrity": "sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==", + "node_modules/listr2/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": { - "postcss-value-parser": "^4.2.0" + "ansi-regex": "^6.0.1" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": ">=12" }, - "peerDependencies": { - "postcss": "^8.2.15" + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/postcss-normalize-timing-functions": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz", - "integrity": "sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==", + "node_modules/listr2/node_modules/wrap-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "dev": true, "dependencies": { - "postcss-value-parser": "^4.2.0" + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": ">=18" }, - "peerDependencies": { - "postcss": "^8.2.15" + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/postcss-normalize-unicode": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz", - "integrity": "sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==", - "dependencies": { - "browserslist": "^4.21.4", - "postcss-value-parser": "^4.2.0" - }, + "node_modules/loader-utils": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", + "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", + "dev": true, "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" + "node": ">= 12.13.0" } }, - "node_modules/postcss-normalize-url": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz", - "integrity": "sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==", + "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": { - "normalize-url": "^6.0.1", - "postcss-value-parser": "^4.2.0" + "p-locate": "^4.1.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" + "node": ">=8" } }, - "node_modules/postcss-normalize-whitespace": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz", - "integrity": "sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "node_modules/postcss-opacity-percentage": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/postcss-opacity-percentage/-/postcss-opacity-percentage-1.1.3.tgz", - "integrity": "sha512-An6Ba4pHBiDtyVpSLymUUERMo2cU7s+Obz6BTrS+gxkbnSBNKSuD0AVUc+CpBMrpVPKKfoVz0WQCX+Tnst0i4A==", - "funding": [ - { - "type": "kofi", - "url": "https://ko-fi.com/mrcgrtz" - }, - { - "type": "liberapay", - "url": "https://liberapay.com/mrcgrtz" - } - ], - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.2" + "node_modules/lodash._reinterpolate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "integrity": "sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==" + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "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==", + "dev": true + }, + "node_modules/lodash.flow": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/lodash.flow/-/lodash.flow-3.5.0.tgz", + "integrity": "sha512-ff3BX/tSioo+XojX4MOsOMhJw0nZoUEF011LX8g8d3gvjVbxd89cCio4BCXronjxcTUIJUoqKEUA+n4CqvvRPw==" + }, + "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, + "peer": true + }, + "node_modules/lodash.template": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", + "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", + "dependencies": { + "lodash._reinterpolate": "^3.0.0", + "lodash.templatesettings": "^4.0.0" } }, - "node_modules/postcss-ordered-values": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz", - "integrity": "sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==", + "node_modules/lodash.templatesettings": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", + "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", "dependencies": { - "cssnano-utils": "^3.1.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" + "lodash._reinterpolate": "^3.0.0" } }, - "node_modules/postcss-overflow-shorthand": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-3.0.4.tgz", - "integrity": "sha512-otYl/ylHK8Y9bcBnPLo3foYFLL6a6Ak+3EQBPOTR7luMYCOsiVTUk1iLvNf6tVPNGXcoL9Hoz37kpfriRIFb4A==", + "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==", "dependencies": { - "postcss-value-parser": "^4.2.0" + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" }, "engines": { - "node": "^12 || ^14 || >=16" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" - } - }, - "node_modules/postcss-page-break": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-3.0.4.tgz", - "integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==", - "peerDependencies": { - "postcss": "^8" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/postcss-place": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-7.0.5.tgz", - "integrity": "sha512-wR8igaZROA6Z4pv0d+bvVrvGY4GVHihBCBQieXFY3kuSuMyOmEnnfFzHl/tQuqHZkfkIVBEbDvYcFfHmpSet9g==", + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dependencies": { - "postcss-value-parser": "^4.2.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": "^12 || ^14 || >=16" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/postcss-preset-env": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-7.8.3.tgz", - "integrity": "sha512-T1LgRm5uEVFSEF83vHZJV2z19lHg4yJuZ6gXZZkqVsqv63nlr6zabMH3l4Pc01FQCyfWVrh2GaUeCVy9Po+Aag==", - "dependencies": { - "@csstools/postcss-cascade-layers": "^1.1.1", - "@csstools/postcss-color-function": "^1.1.1", - "@csstools/postcss-font-format-keywords": "^1.0.1", - "@csstools/postcss-hwb-function": "^1.0.2", - "@csstools/postcss-ic-unit": "^1.0.1", - "@csstools/postcss-is-pseudo-class": "^2.0.7", - "@csstools/postcss-nested-calc": "^1.0.0", - "@csstools/postcss-normalize-display-values": "^1.0.1", - "@csstools/postcss-oklab-function": "^1.1.1", - "@csstools/postcss-progressive-custom-properties": "^1.3.0", - "@csstools/postcss-stepped-value-functions": "^1.0.1", - "@csstools/postcss-text-decoration-shorthand": "^1.0.0", - "@csstools/postcss-trigonometric-functions": "^1.0.2", - "@csstools/postcss-unset-value": "^1.0.2", - "autoprefixer": "^10.4.13", - "browserslist": "^4.21.4", - "css-blank-pseudo": "^3.0.3", - "css-has-pseudo": "^3.0.4", - "css-prefers-color-scheme": "^6.0.3", - "cssdb": "^7.1.0", - "postcss-attribute-case-insensitive": "^5.0.2", - "postcss-clamp": "^4.1.0", - "postcss-color-functional-notation": "^4.2.4", - "postcss-color-hex-alpha": "^8.0.4", - "postcss-color-rebeccapurple": "^7.1.1", - "postcss-custom-media": "^8.0.2", - "postcss-custom-properties": "^12.1.10", - "postcss-custom-selectors": "^6.0.3", - "postcss-dir-pseudo-class": "^6.0.5", - "postcss-double-position-gradients": "^3.1.2", - "postcss-env-function": "^4.0.6", - "postcss-focus-visible": "^6.0.4", - "postcss-focus-within": "^5.0.4", - "postcss-font-variant": "^5.0.0", - "postcss-gap-properties": "^3.0.5", - "postcss-image-set-function": "^4.0.7", - "postcss-initial": "^4.0.1", - "postcss-lab-function": "^4.2.1", - "postcss-logical": "^5.0.4", - "postcss-media-minmax": "^5.0.0", - "postcss-nesting": "^10.2.0", - "postcss-opacity-percentage": "^1.1.2", - "postcss-overflow-shorthand": "^3.0.4", - "postcss-page-break": "^3.0.4", - "postcss-place": "^7.0.5", - "postcss-pseudo-class-any-link": "^7.1.6", - "postcss-replace-overflow-wrap": "^4.0.0", - "postcss-selector-not": "^6.0.1", - "postcss-value-parser": "^4.2.0" + "node_modules/log-update": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", + "dev": true, + "dependencies": { + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" }, "engines": { - "node": "^12 || ^14 || >=16" + "node": ">=18" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/postcss-pseudo-class-any-link": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-7.1.6.tgz", - "integrity": "sha512-9sCtZkO6f/5ML9WcTLcIyV1yz9D1rf0tWc+ulKcvV30s0iZKS/ONyETvoWsr6vnrmW+X+KmuK3gV/w5EWnT37w==", + "node_modules/log-update/node_modules/ansi-escapes": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz", + "integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==", + "dev": true, "dependencies": { - "postcss-selector-parser": "^6.0.10" + "environment": "^1.0.0" }, "engines": { - "node": "^12 || ^14 || >=16" + "node": ">=18" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/postcss-reduce-initial": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz", - "integrity": "sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==", - "dependencies": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0" - }, + "node_modules/log-update/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": "^10 || ^12 || >=14.0" + "node": ">=12" }, - "peerDependencies": { - "postcss": "^8.2.15" + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/postcss-reduce-transforms": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz", - "integrity": "sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, + "node_modules/log-update/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": ">=12" }, - "peerDependencies": { - "postcss": "^8.2.15" + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/postcss-replace-overflow-wrap": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz", - "integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==", - "peerDependencies": { - "postcss": "^8.0.3" - } + "node_modules/log-update/node_modules/emoji-regex": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "dev": true }, - "node_modules/postcss-selector-not": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-6.0.1.tgz", - "integrity": "sha512-1i9affjAe9xu/y9uqWH+tD4r6/hDaXJruk8xn2x1vzxC2U3J3LKO3zJW4CyxlNhA56pADJ/djpEwpH1RClI2rQ==", + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz", + "integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==", + "dev": true, "dependencies": { - "postcss-selector-parser": "^6.0.10" + "get-east-asian-width": "^1.0.0" }, "engines": { - "node": "^12 || ^14 || >=16" + "node": ">=18" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.0.13", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", - "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/postcss-svgo": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.1.0.tgz", - "integrity": "sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==", + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz", + "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==", + "dev": true, "dependencies": { - "postcss-value-parser": "^4.2.0", - "svgo": "^2.7.0" + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": ">=18" }, - "peerDependencies": { - "postcss": "^8.2.15" + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "node_modules/postcss-svgo/node_modules/commander": { + "node_modules/log-update/node_modules/string-width": { "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/postcss-svgo/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==", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "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" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/fb55" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/postcss-svgo/node_modules/css-tree": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", - "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "node_modules/log-update/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": { - "mdn-data": "2.0.14", - "source-map": "^0.6.1" + "ansi-regex": "^6.0.1" }, "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/postcss-svgo/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==", - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" + "node": ">=12" }, "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/postcss-svgo/node_modules/domhandler": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "dev": true, "dependencies": { - "domelementtype": "^2.2.0" + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">= 4" + "node": ">=18" }, "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/postcss-svgo/node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "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": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" + "js-tokens": "^3.0.0 || ^4.0.0" }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" + "bin": { + "loose-envify": "cli.js" } }, - "node_modules/postcss-svgo/node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "funding": { - "url": "https://github.com/fb55/entities?sponsor=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" } }, - "node_modules/postcss-svgo/node_modules/mdn-data": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", - "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" - }, - "node_modules/postcss-svgo/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==", + "node_modules/lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/postcss-svgo/node_modules/svgo": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", - "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", - "dependencies": { - "@trysound/sax": "0.2.0", - "commander": "^7.2.0", - "css-select": "^4.1.3", - "css-tree": "^1.1.3", - "csso": "^4.2.0", - "picocolors": "^1.0.0", - "stable": "^0.1.8" - }, - "bin": { - "svgo": "bin/svgo" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/postcss-unique-selectors": { + "node_modules/lru-cache": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz", - "integrity": "sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dependencies": { - "postcss-selector-parser": "^6.0.5" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" + "yallist": "^3.0.2" } }, - "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==" - }, - "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==", - "engines": { - "node": ">= 0.8.0" - } + "node_modules/lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==" }, - "node_modules/prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==", + "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, - "engines": { - "node": ">=4" - } - }, - "node_modules/prettier": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", - "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "peer": true, "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" + "lz-string": "bin/bin.js" } }, - "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==", + "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": { - "fast-diff": "^1.1.2" + "semver": "^6.0.0" }, "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/pretty-bytes": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", - "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", - "engines": { - "node": ">=6" + "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", - "dependencies": { - "lodash": "^4.17.20", - "renderkid": "^3.0.0" + "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/pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", "dev": true, "dependencies": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": ">= 10" + "tmpl": "1.0.5" } }, - "node_modules/pretty-format/node_modules/@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, + "node_modules/markdown-it": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, + "node_modules/markdown-it/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/markdown-link": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/markdown-link/-/markdown-link-0.1.1.tgz", + "integrity": "sha512-TurLymbyLyo+kAUUAV9ggR9EPcDjP/ctlv9QAFiqUH7c+t6FlsbivPo9OKTU8xdOx9oNd2drW/Fi5RRElQbUqA==", "engines": { - "node": ">= 10.14.2" + "node": ">=0.10.0" } }, - "node_modules/pretty-format/node_modules/@types/yargs": { - "version": "15.0.15", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.15.tgz", - "integrity": "sha512-IziEYMU9XoVj8hWg7k+UJrXALkGFjWJhn5QFEv9q4p+v40oZhSuC135M38st8XPjICL7Ey4TV64ferBGUoJhBg==", - "dev": true, + "node_modules/markdown-toc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/markdown-toc/-/markdown-toc-1.2.0.tgz", + "integrity": "sha512-eOsq7EGd3asV0oBfmyqngeEIhrbkc7XVP63OwcJBIhH2EpG2PzFcbZdhy1jutXSlRBBVMNXHvMtSr5LAxSUvUg==", "dependencies": { - "@types/yargs-parser": "*" + "concat-stream": "^1.5.2", + "diacritics-map": "^0.1.0", + "gray-matter": "^2.1.0", + "lazy-cache": "^2.0.2", + "list-item": "^1.1.1", + "markdown-link": "^0.1.1", + "minimist": "^1.2.0", + "mixin-deep": "^1.1.3", + "object.pick": "^1.2.0", + "remarkable": "^1.7.1", + "repeat-string": "^1.6.1", + "strip-color": "^0.1.0" + }, + "bin": { + "markdown-toc": "cli.js" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/pretty-format/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/math-random": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", + "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==" + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz", + "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "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/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==" }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + "node_modules/memoize-one": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", + "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==" }, - "node_modules/promise": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", - "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", - "dependencies": { - "asap": "~2.0.6" - } + "node_modules/merge": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/merge/-/merge-2.1.1.tgz", + "integrity": "sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w==", + "dev": true }, - "node_modules/promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", - "optional": true, - "peer": 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/promise-retry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "optional": true, - "peer": true, - "dependencies": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - }, + "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": ">=10" + "node": ">= 8" } }, - "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==", + "node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "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==", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } + "node_modules/micromark-util-encode": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz", + "integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] }, - "node_modules/prop-types-extra": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz", - "integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==", + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz", + "integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "dependencies": { - "react-is": "^16.3.2", - "warning": "^4.0.0" - }, - "peerDependencies": { - "react": ">=0.14.0" + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/prop-types-extra/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/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] }, - "node_modules/prop-types/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/micromark-util-types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", + "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] }, - "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==", + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" + "braces": "^3.0.3", + "picomatch": "^2.3.1" }, "engines": { - "node": ">= 0.10" + "node": ">=8.6" } }, - "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==", + "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.10" + "node": ">= 0.6" } }, - "node_modules/psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "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": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" } }, - "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "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==", "engines": { "node": ">=6" } }, - "node_modules/pupa": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", - "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", "dev": true, - "dependencies": { - "escape-goat": "^2.0.0" + "engines": { + "node": ">=18" }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true, "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "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": ">=0.6.0", - "teleport": ">=0.2.0" + "node": ">=4" } }, - "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "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": { - "side-channel": "^1.0.4" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=0.6" - }, + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" + "node_modules/mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dependencies": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } }, - "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==", - "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/mrmime": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", + "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==", + "dev": true, + "engines": { + "node": ">=10" + } }, - "node_modules/quick-lru": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", - "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", - "optional": true, - "peer": true, + "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/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, "engines": { - "node": ">=8" + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/raf": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", - "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "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/no-case": { + "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": { - "performance-now": "^2.1.0" + "lower-case": "^2.0.2", + "tslib": "^2.0.3" } }, - "node_modules/randomatic": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz", - "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==", + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "dependencies": { - "is-number": "^4.0.0", - "kind-of": "^6.0.0", - "math-random": "^1.0.1" + "whatwg-url": "^5.0.0" }, "engines": { - "node": ">= 0.10.0" + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } } }, - "node_modules/randomatic/node_modules/is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "engines": { - "node": ">=0.10.0" + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" } }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "node_modules/node-html-better-parser": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/node-html-better-parser/-/node-html-better-parser-1.4.4.tgz", + "integrity": "sha512-uvlqL1uMU7m/aIY9WsGM0jDW7gVFIuFSWS6f2rlJeL7K1ZzKnA3B8cNbUGw9ywwYm9W7W2ooi0iQ7aI29aQmPw==", + "license": "MIT", "dependencies": { - "safe-buffer": "^5.1.0" + "html-entities": "^2.3.2" } }, - "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==", + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true + }, + "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==" + }, + "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==", + "devOptional": true, "engines": { - "node": ">= 0.6" + "node": ">=0.10.0" } }, - "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "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": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" + "path-key": "^3.0.0" }, "engines": { - "node": ">= 0.8" + "node": ">=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==", - "engines": { - "node": ">= 0.8" - } + "node_modules/nwsapi": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", + "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==", + "dev": true }, - "node_modules/raw-body/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==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, + "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==", "engines": { "node": ">=0.10.0" } }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", "dev": true, - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/rc/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "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.10.0" + "node": ">= 0.4" } }, - "node_modules/react": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", - "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", + "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": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/react-app-polyfill": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-3.0.0.tgz", - "integrity": "sha512-sZ41cxiU5llIB003yxxQBYrARBqe0repqPTTYBTmMqTz9szeBbE37BehCE891NZsmdZqqP+xWKdT3eo3vOzN8w==", + "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": { - "core-js": "^3.19.2", - "object-assign": "^4.1.1", - "promise": "^8.1.0", - "raf": "^3.4.1", - "regenerator-runtime": "^0.13.9", - "whatwg-fetch": "^3.6.2" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "engines": { - "node": ">=14" + "node": ">= 0.4" } }, - "node_modules/react-app-rewired": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/react-app-rewired/-/react-app-rewired-2.2.1.tgz", - "integrity": "sha512-uFQWTErXeLDrMzOJHKp0h8P1z0LV9HzPGsJ6adOtGlA/B9WfT6Shh4j2tLTTGlXOfiVx6w6iWpp7SOC5pvk+gA==", + "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": { - "semver": "^5.6.0" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" }, - "bin": { - "react-app-rewired": "bin/index.js" + "engines": { + "node": ">= 0.4" }, - "peerDependencies": { - "react-scripts": ">=2.1.3" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/react-app-rewired/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "bin": { - "semver": "bin/semver" + "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/react-async-script": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/react-async-script/-/react-async-script-1.2.0.tgz", - "integrity": "sha512-bCpkbm9JiAuMGhkqoAiC0lLkb40DJ0HOEJIku+9JDjxX3Rcs+ztEOG13wbrOskt3n2DTrjshhaQ/iay+SnGg5Q==", + "node_modules/object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", "dependencies": { - "hoist-non-react-statics": "^3.3.0", - "prop-types": "^15.5.0" + "isobject": "^3.0.1" }, - "peerDependencies": { - "react": ">=16.4.1" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/react-bootstrap": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.8.0.tgz", - "integrity": "sha512-e/aNtxl0Z2ozrIaR82jr6Zz7ss9GSoaXpQaxmvtDUsTZIq/XalkduR/ZXP6vbQHz2T4syvjA+4FbtwELxxmpww==", + "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": { - "@babel/runtime": "^7.21.0", - "@restart/hooks": "^0.4.9", - "@restart/ui": "^1.6.3", - "@types/react-transition-group": "^4.4.5", - "classnames": "^2.3.2", - "dom-helpers": "^5.2.1", - "invariant": "^2.2.4", - "prop-types": "^15.8.1", - "prop-types-extra": "^1.1.0", - "react-transition-group": "^4.4.5", - "uncontrollable": "^7.2.1", - "warning": "^4.0.3" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, - "peerDependencies": { - "@types/react": ">=16.14.8", - "react": ">=16.14.0", - "react-dom": ">=16.14.0" + "engines": { + "node": ">= 0.4" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/react-chartjs-2": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.2.0.tgz", - "integrity": "sha512-98iN5aguJyVSxp5U3CblRLH67J8gkfyGNbiK3c+l1QI/G4irHMPQw44aEPmjVag+YKTyQ260NcF82GTQ3bdscA==", - "peerDependencies": { - "chart.js": "^4.1.1", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" } }, - "node_modules/react-datepicker": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-4.16.0.tgz", - "integrity": "sha512-hNQ0PAg/LQoVbDUO/RWAdm/RYmPhN3cz7LuQ3hqbs24OSp69QCiKOJRrQ4jk1gv1jNR5oYu8SjjgfDh8q6Q1yw==", + "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": { - "@popperjs/core": "^2.11.8", - "classnames": "^2.2.6", - "date-fns": "^2.30.0", - "prop-types": "^15.7.2", - "react-onclickoutside": "^6.12.2", - "react-popper": "^2.3.0" - }, - "peerDependencies": { - "react": "^16.9.0 || ^17 || ^18", - "react-dom": "^16.9.0 || ^17 || ^18" + "wrappy": "1" } }, - "node_modules/react-dev-utils": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", - "integrity": "sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==", + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dependencies": { - "@babel/code-frame": "^7.16.0", - "address": "^1.1.2", - "browserslist": "^4.18.1", - "chalk": "^4.1.2", - "cross-spawn": "^7.0.3", - "detect-port-alt": "^1.1.6", - "escape-string-regexp": "^4.0.0", - "filesize": "^8.0.6", - "find-up": "^5.0.0", - "fork-ts-checker-webpack-plugin": "^6.5.0", - "global-modules": "^2.0.0", - "globby": "^11.0.4", - "gzip-size": "^6.0.0", - "immer": "^9.0.7", - "is-root": "^2.1.0", - "loader-utils": "^3.2.0", - "open": "^8.4.0", - "pkg-up": "^3.1.0", - "prompts": "^2.4.2", - "react-error-overlay": "^6.0.11", - "recursive-readdir": "^2.2.2", - "shell-quote": "^1.7.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" + "mimic-fn": "^2.1.0" }, "engines": { - "node": ">=14" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/react-dev-utils/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/oniguruma-to-js": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/oniguruma-to-js/-/oniguruma-to-js-0.4.3.tgz", + "integrity": "sha512-X0jWUcAlxORhOqqBREgPMgnshB7ZGYszBNspP+tS9hPD3l13CdaXcHbgImoHUHlrvGx/7AvFEkTRhAGYh+jzjQ==", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" + "regex": "^4.3.2" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/antfu" } }, - "node_modules/react-dev-utils/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==", + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" }, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/react-dev-utils/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==", + "node_modules/optimism": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/optimism/-/optimism-0.18.0.tgz", + "integrity": "sha512-tGn8+REwLRNFnb9WmcY5IfpOqeX2kpaYJ1s6Ae3mn12AeydLkR3j+jSCmVQFoXqU8D41PAJ1RG1rCRNWmNZVmQ==", "dependencies": { - "p-locate": "^5.0.0" + "@wry/caches": "^1.0.0", + "@wry/context": "^0.7.0", + "@wry/trie": "^0.4.3", + "tslib": "^2.3.0" + } + }, + "node_modules/optimism/node_modules/@wry/trie": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@wry/trie/-/trie-0.4.3.tgz", + "integrity": "sha512-I6bHwH0fSf6RqQcnnXLJKhkSXG45MFral3GxPaY4uAl0LYDZM+YDVDAiU9bYwjTuysy1S0IeecWtmq1SZA3M1w==", + "dependencies": { + "tslib": "^2.3.0" }, "engines": { - "node": ">=10" + "node": ">=8" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "peer": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">= 0.8.0" } }, - "node_modules/react-dev-utils/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==", + "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==", "dependencies": { - "yocto-queue": "^0.1.0" + "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" @@ -20374,1768 +18191,1787 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/react-dev-utils/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==", + "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==", "dependencies": { - "p-limit": "^3.0.2" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/react-dom": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", - "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", + "node_modules/ora/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==", "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "scheduler": "^0.20.2" + "restore-cursor": "^3.1.0" }, - "peerDependencies": { - "react": "17.0.2" + "engines": { + "node": ">=8" } }, - "node_modules/react-error-overlay": { - "version": "6.0.11", - "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", - "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" + "node_modules/ora/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==", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } }, - "node_modules/react-fast-compare": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", - "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==" + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/react-google-recaptcha": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/react-google-recaptcha/-/react-google-recaptcha-2.1.0.tgz", - "integrity": "sha512-K9jr7e0CWFigi8KxC3WPvNqZZ47df2RrMAta6KmRoE4RUi7Ys6NmNjytpXpg4HI/svmQJLKR+PncEPaNJ98DqQ==", + "node_modules/p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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": { - "prop-types": "^15.5.0", - "react-async-script": "^1.1.1" + "p-try": "^2.0.0" }, - "peerDependencies": { - "react": ">=16.4.1" + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/react-i18next": { - "version": "11.18.6", - "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.18.6.tgz", - "integrity": "sha512-yHb2F9BiT0lqoQDt8loZ5gWP331GwctHz9tYQ8A2EIEUu+CcEdjBLQWli1USG3RdWQt3W+jqQLg/d4rrQR96LA==", + "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": { - "@babel/runtime": "^7.14.5", - "html-parse-stringify": "^3.0.1" - }, - "peerDependencies": { - "i18next": ">= 19.0.0", - "react": ">= 16.8.0" + "p-limit": "^2.2.0" }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - }, - "react-native": { - "optional": true - } + "engines": { + "node": ">=8" } }, - "node_modules/react-icons": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.2.1.tgz", - "integrity": "sha512-zdbW5GstTzXaVKvGSyTaBalt7HSfuK5ovrzlpyiWHAFXndXTdd/1hdDHI4xBM1Mn7YriT6aqESucFl9kEXzrdw==", - "peerDependencies": { - "react": "*" + "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/react-infinite-scroll-component": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/react-infinite-scroll-component/-/react-infinite-scroll-component-6.1.0.tgz", - "integrity": "sha512-SQu5nCqy8DxQWpnUVLx7V7b7LcA37aM7tvoWjTLZp1dk6EJibM5/4EJKzOnl07/BsM1Y40sKLuqjCwwH/xV0TQ==", + "node_modules/package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "dev": true, "dependencies": { - "throttle-debounce": "^2.1.0" + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" }, - "peerDependencies": { - "react": ">=16.0.0" + "engines": { + "node": ">=8" } }, - "node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" - }, - "node_modules/react-lifecycles-compat": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", - "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" - }, - "node_modules/react-onclickoutside": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/react-onclickoutside/-/react-onclickoutside-6.13.0.tgz", - "integrity": "sha512-ty8So6tcUpIb+ZE+1HAhbLROvAIJYyJe/1vRrrcmW+jLsaM+/powDRqxzo6hSh9CuRZGSL1Q8mvcF5WRD93a0A==", - "funding": { - "type": "individual", - "url": "https://github.com/Pomax/react-onclickoutside/blob/master/FUNDING.md" - }, - "peerDependencies": { - "react": "^15.5.x || ^16.x || ^17.x || ^18.x", - "react-dom": "^15.5.x || ^16.x || ^17.x || ^18.x" + "node_modules/package-json/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/react-popper": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.3.0.tgz", - "integrity": "sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==", + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, + "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": { - "react-fast-compare": "^3.0.1", - "warning": "^4.0.2" + "callsites": "^3.0.0" }, - "peerDependencies": { - "@popperjs/core": "^2.0.0", - "react": "^16.8.0 || ^17 || ^18", - "react-dom": "^16.8.0 || ^17 || ^18" + "engines": { + "node": ">=6" } }, - "node_modules/react-redux": { - "version": "7.2.9", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.9.tgz", - "integrity": "sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ==", + "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/runtime": "^7.15.4", - "@types/react-redux": "^7.1.20", - "hoist-non-react-statics": "^3.3.2", - "loose-envify": "^1.4.0", - "prop-types": "^15.7.2", - "react-is": "^17.0.2" + "@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" }, - "peerDependencies": { - "react": "^16.8.3 || ^17 || ^18" + "engines": { + "node": ">=8" }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - }, - "react-native": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/react-redux/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==" - }, - "node_modules/react-refresh": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", - "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==", + "node_modules/parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", + "dev": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/react-router": { - "version": "6.23.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.23.1.tgz", - "integrity": "sha512-fzcOaRF69uvqbbM7OhvQyBTFDVrrGlsFdS3AL+1KfIBtGETibHzi3FkoTRyiDJnWNc2VxrfvR+657ROHjaNjqQ==", - "dependencies": { - "@remix-run/router": "1.16.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "react": ">=16.8" - } + "node_modules/parse-srcset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz", + "integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==" }, - "node_modules/react-router-dom": { - "version": "6.23.1", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.23.1.tgz", - "integrity": "sha512-utP+K+aSTtEdbWpC+4gxhdlPFwuEfDKq8ZrPFU65bbRJY+l706qjR7yaidBpo3MSeA/fzwbXWbKBI6ftOnP3OQ==", - "dependencies": { - "@remix-run/router": "1.16.1", - "react-router": "6.23.1" - }, + "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": ">=14.0.0" - }, - "peerDependencies": { - "react": ">=16.8", - "react-dom": ">=16.8" + "node": ">= 0.8" } }, - "node_modules/react-scripts": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", - "integrity": "sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ==", - "dependencies": { - "@babel/core": "^7.16.0", - "@pmmmwh/react-refresh-webpack-plugin": "^0.5.3", - "@svgr/webpack": "^5.5.0", - "babel-jest": "^27.4.2", - "babel-loader": "^8.2.3", - "babel-plugin-named-asset-import": "^0.3.8", - "babel-preset-react-app": "^10.0.1", - "bfj": "^7.0.2", - "browserslist": "^4.18.1", - "camelcase": "^6.2.1", - "case-sensitive-paths-webpack-plugin": "^2.4.0", - "css-loader": "^6.5.1", - "css-minimizer-webpack-plugin": "^3.2.0", - "dotenv": "^10.0.0", - "dotenv-expand": "^5.1.0", - "eslint": "^8.3.0", - "eslint-config-react-app": "^7.0.1", - "eslint-webpack-plugin": "^3.1.1", - "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "html-webpack-plugin": "^5.5.0", - "identity-obj-proxy": "^3.0.0", - "jest": "^27.4.3", - "jest-resolve": "^27.4.2", - "jest-watch-typeahead": "^1.0.0", - "mini-css-extract-plugin": "^2.4.5", - "postcss": "^8.4.4", - "postcss-flexbugs-fixes": "^5.0.2", - "postcss-loader": "^6.2.1", - "postcss-normalize": "^10.0.1", - "postcss-preset-env": "^7.0.1", - "prompts": "^2.4.2", - "react-app-polyfill": "^3.0.0", - "react-dev-utils": "^12.0.1", - "react-refresh": "^0.11.0", - "resolve": "^1.20.0", - "resolve-url-loader": "^4.0.0", - "sass-loader": "^12.3.0", - "semver": "^7.3.5", - "source-map-loader": "^3.0.0", - "style-loader": "^3.3.1", - "tailwindcss": "^3.0.2", - "terser-webpack-plugin": "^5.2.5", - "webpack": "^5.64.4", - "webpack-dev-server": "^4.6.0", - "webpack-manifest-plugin": "^4.0.2", - "workbox-webpack-plugin": "^6.4.1" - }, - "bin": { - "react-scripts": "bin/react-scripts.js" - }, + "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": ">=14.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - }, - "peerDependencies": { - "react": ">= 16", - "typescript": "^3.2.1 || ^4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "node": ">=8" } }, - "node_modules/react-scripts/node_modules/babel-jest": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", - "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", - "dependencies": { - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^27.5.1", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, + "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": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" + "node": ">=0.10.0" } }, - "node_modules/react-scripts/node_modules/babel-plugin-jest-hoist": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz", - "integrity": "sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==", - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.0.0", - "@types/babel__traverse": "^7.0.6" - }, + "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": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=8" } }, - "node_modules/react-scripts/node_modules/babel-preset-jest": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz", - "integrity": "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==", - "dependencies": { - "babel-plugin-jest-hoist": "^27.5.1", - "babel-preset-current-node-syntax": "^1.0.0" - }, + "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-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": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node": ">=8" } }, - "node_modules/react-scripts/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "node_modules/picocolors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "devOptional": true, "engines": { - "node": ">=10" + "node": ">=8.6" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/react-scripts/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "bin": { + "pidtree": "bin/pidtree.js" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=0.10" } }, - "node_modules/react-toastify": { - "version": "9.1.3", - "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-9.1.3.tgz", - "integrity": "sha512-fPfb8ghtn/XMxw3LkxQBk3IyagNpF/LIKjOBflbexr2AWxAH1MJgvnESwEwBn9liLFXgTKWgBSdZpw9m4OTHTg==", - "dependencies": { - "clsx": "^1.1.1" - }, - "peerDependencies": { - "react": ">=16", - "react-dom": ">=16" + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/react-transition-group": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", - "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "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": { - "@babel/runtime": "^7.5.5", - "dom-helpers": "^5.0.1", - "loose-envify": "^1.4.0", - "prop-types": "^15.6.2" + "find-up": "^4.0.0" }, - "peerDependencies": { - "react": ">=16.6.0", - "react-dom": ">=16.6.0" + "engines": { + "node": ">=8" } }, - "node_modules/read-cache": { + "node_modules/possible-typed-array-names": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "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.45", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.45.tgz", + "integrity": "sha512-7KTLTdzdZZYscUc65XmjFiB73vBhBfbPztCYdUNvlaso9PrzjzcmjqBPR0lNGkcVlcO4BjiO5rK/qNz+XAen1Q==", + "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": { - "pify": "^2.3.0" + "nanoid": "^3.3.7", + "picocolors": "^1.0.1", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" } }, - "node_modules/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "optional": true, - "peer": true, + "node_modules/postcss-import": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.1.0.tgz", + "integrity": "sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==", + "dev": true, "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" }, "engines": { - "node": ">=8" + "node": ">=10.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" } }, - "node_modules/read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "optional": true, - "peer": true, + "node_modules/postcss-load-config": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz", + "integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==", + "dev": true, "dependencies": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" + "lilconfig": "^2.0.5", + "yaml": "^2.1.1" }, "engines": { - "node": ">=8" + "node": ">= 14" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } } }, - "node_modules/read-pkg-up/node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "optional": true, - "peer": true, + "node_modules/postcss-load-config/node_modules/yaml": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz", + "integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==", + "dev": true, "engines": { - "node": ">=8" + "node": ">= 14" } }, - "node_modules/read-pkg/node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "optional": true, - "peer": true - }, - "node_modules/read-pkg/node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "optional": true, - "peer": true, + "node_modules/postcss-modules": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules/-/postcss-modules-6.0.0.tgz", + "integrity": "sha512-7DGfnlyi/ju82BRzTIjWS5C4Tafmzl3R79YP/PASiocj+aa6yYphHhhKUOEoXQToId5rgyFgJ88+ccOUydjBXQ==", + "dev": true, "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/read-pkg/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "optional": true, - "peer": true, - "bin": { - "semver": "bin/semver" + "generic-names": "^4.0.0", + "icss-utils": "^5.1.0", + "lodash.camelcase": "^4.3.0", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.0", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "string-hash": "^1.1.1" + }, + "peerDependencies": { + "postcss": "^8.0.0" } }, - "node_modules/read-pkg/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "optional": true, - "peer": true, + "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": ">=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==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "node": "^10 || ^12 || >= 14" }, - "engines": { - "node": ">= 6" + "peerDependencies": { + "postcss": "^8.1.0" } }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "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": { - "picomatch": "^2.2.1" + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" }, "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/recursive-readdir": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", - "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", - "dependencies": { - "minimatch": "^3.0.5" + "node": "^10 || ^12 || >= 14" }, - "engines": { - "node": ">=6.0.0" + "peerDependencies": { + "postcss": "^8.1.0" } }, - "node_modules/redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", - "devOptional": true, + "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": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" + "postcss-selector-parser": "^6.0.4" }, "engines": { - "node": ">=8" - } - }, - "node_modules/redux": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", - "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", - "dependencies": { - "@babel/runtime": "^7.9.2" - } - }, - "node_modules/redux-thunk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz", - "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==", + "node": "^10 || ^12 || >= 14" + }, "peerDependencies": { - "redux": "^4" + "postcss": "^8.1.0" } }, - "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==", + "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": { - "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" + "icss-utils": "^5.0.0" }, "engines": { - "node": ">= 0.4" + "node": "^10 || ^12 || >= 14" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "postcss": "^8.1.0" } }, - "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.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", - "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", + "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": { - "regenerate": "^1.4.2" + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" }, "engines": { "node": ">=4" } }, - "node_modules/regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" - }, - "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/regex-parser": { - "version": "2.2.11", - "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz", - "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==" + "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/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==", - "dependencies": { - "call-bind": "^1.0.6", - "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "set-function-name": "^2.0.1" - }, + "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, + "peer": true, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 0.8.0" } }, - "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" - }, + "node_modules/prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==", + "dev": true, "engines": { "node": ">=4" } }, - "node_modules/registry-auth-token": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.2.tgz", - "integrity": "sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==", + "node_modules/prettier": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", + "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": { - "rc": "1.2.8" + "fast-diff": "^1.1.2" }, "engines": { "node": ">=6.0.0" } }, - "node_modules/registry-url": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", - "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "node_modules/pretty-format": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", + "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", "dev": true, "dependencies": { - "rc": "^1.2.8" + "@jest/types": "^26.6.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^17.0.1" }, "engines": { - "node": ">=8" + "node": ">= 10" } }, - "node_modules/regjsparser": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", - "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "node_modules/pretty-format/node_modules/@jest/types": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", + "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "dev": true, "dependencies": { - "jsesc": "~0.5.0" + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" }, - "bin": { - "regjsparser": "bin/parser" + "engines": { + "node": ">= 10.14.2" } }, - "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/pretty-format/node_modules/@types/yargs": { + "version": "15.0.15", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.15.tgz", + "integrity": "sha512-IziEYMU9XoVj8hWg7k+UJrXALkGFjWJhn5QFEv9q4p+v40oZhSuC135M38st8XPjICL7Ey4TV64ferBGUoJhBg==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" } }, - "node_modules/relateurl": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", - "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "node_modules/pretty-format/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": ">= 0.10" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/remarkable": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/remarkable/-/remarkable-1.7.4.tgz", - "integrity": "sha512-e6NKUXgX95whv7IgddywbeN/ItCkWbISmc2DiqHJb0wTrqZIexqdco5b8Z3XZoo/48IdNVKM9ZCvTPJ4F5uvhg==", + "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-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "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": { - "argparse": "^1.0.10", - "autolinker": "~0.28.0" - }, - "bin": { - "remarkable": "bin/remarkable.js" + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" }, "engines": { - "node": ">= 0.10.0" + "node": ">= 6" } }, - "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==", + "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==", "dependencies": { - "css-select": "^4.1.3", - "dom-converter": "^0.2.0", - "htmlparser2": "^6.1.0", - "lodash": "^4.17.21", - "strip-ansi": "^6.0.1" + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" } }, - "node_modules/renderkid/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==", + "node_modules/prop-types-extra": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz", + "integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==", "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.0.1", - "domhandler": "^4.3.1", - "domutils": "^2.8.0", - "nth-check": "^2.0.1" + "react-is": "^16.3.2", + "warning": "^4.0.0" }, - "funding": { - "url": "https://github.com/sponsors/fb55" + "peerDependencies": { + "react": ">=0.14.0" } }, - "node_modules/renderkid/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==", - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - }, + "node_modules/prop-types-extra/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/prop-types/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/property-information": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", + "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/renderkid/node_modules/domhandler": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, "dependencies": { - "domelementtype": "^2.2.0" - }, + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true, "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" + "node": ">=6" + } + }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "engines": { + "node": ">=6" } }, - "node_modules/renderkid/node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "node_modules/pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "dev": true, "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" + "escape-goat": "^2.0.0" }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" + "engines": { + "node": ">=8" } }, - "node_modules/renderkid/node_modules/entities": { + "node_modules/querystringify": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true }, - "node_modules/renderkid/node_modules/htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "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": [ - "https://github.com/fb55/htmlparser2?sponsor=1", { "type": "github", - "url": "https://github.com/sponsors/fb55" + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" } - ], - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" - } + ] }, - "node_modules/repeat-element": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", - "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", + "node_modules/raf-schd": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz", + "integrity": "sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==" + }, + "node_modules/randomatic": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz", + "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==", + "dependencies": { + "is-number": "^4.0.0", + "kind-of": "^6.0.0", + "math-random": "^1.0.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.10.0" } }, - "node_modules/repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "node_modules/randomatic/node_modules/is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", "engines": { - "node": ">=0.10" + "node": ">=0.10.0" } }, - "node_modules/request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", - "optional": true, - "peer": true, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, "engines": { - "node": ">= 6" + "node": ">=0.10.0" } }, - "node_modules/request/node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "optional": true, - "peer": 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": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" + "loose-envify": "^1.1.0" }, "engines": { - "node": ">= 0.12" + "node": ">=0.10.0" } }, - "node_modules/request/node_modules/qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", - "optional": true, - "peer": true, - "engines": { - "node": ">=0.6" + "node_modules/react-async-script": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/react-async-script/-/react-async-script-1.2.0.tgz", + "integrity": "sha512-bCpkbm9JiAuMGhkqoAiC0lLkb40DJ0HOEJIku+9JDjxX3Rcs+ztEOG13wbrOskt3n2DTrjshhaQ/iay+SnGg5Q==", + "dependencies": { + "hoist-non-react-statics": "^3.3.0", + "prop-types": "^15.5.0" + }, + "peerDependencies": { + "react": ">=16.4.1" } }, - "node_modules/request/node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "optional": true, - "peer": true, + "node_modules/react-beautiful-dnd": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/react-beautiful-dnd/-/react-beautiful-dnd-13.1.1.tgz", + "integrity": "sha512-0Lvs4tq2VcrEjEgDXHjT98r+63drkKEgqyxdA7qD3mvKwga6a5SscbdLPO2IExotU1jW8L0Ksdl0Cj2AF67nPQ==", "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" + "@babel/runtime": "^7.9.2", + "css-box-model": "^1.2.0", + "memoize-one": "^5.1.1", + "raf-schd": "^4.0.2", + "react-redux": "^7.2.0", + "redux": "^4.0.4", + "use-memo-one": "^1.1.1" }, - "engines": { - "node": ">=0.8" + "peerDependencies": { + "react": "^16.8.5 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.5 || ^17.0.0 || ^18.0.0" } }, - "node_modules/request/node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "optional": true, - "peer": true, - "bin": { - "uuid": "bin/uuid" - } + "node_modules/react-beautiful-dnd/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==" }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "engines": { - "node": ">=0.10.0" + "node_modules/react-beautiful-dnd/node_modules/react-redux": { + "version": "7.2.9", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.9.tgz", + "integrity": "sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ==", + "dependencies": { + "@babel/runtime": "^7.15.4", + "@types/react-redux": "^7.1.20", + "hoist-non-react-statics": "^3.3.2", + "loose-envify": "^1.4.0", + "prop-types": "^15.7.2", + "react-is": "^17.0.2" + }, + "peerDependencies": { + "react": "^16.8.3 || ^17 || ^18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } } }, - "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==", - "engines": { - "node": ">=0.10.0" + "node_modules/react-beautiful-dnd/node_modules/redux": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "dependencies": { + "@babel/runtime": "^7.9.2" } }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" - }, - "node_modules/reselect": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.8.tgz", - "integrity": "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==" - }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "node_modules/react-bootstrap": { + "version": "2.10.5", + "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.10.5.tgz", + "integrity": "sha512-XueAOEn64RRkZ0s6yzUTdpFtdUXs5L5491QU//8ZcODKJNDLt/r01tNyriZccjgRImH1REynUc9pqjiRMpDLWQ==", "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" + "@babel/runtime": "^7.24.7", + "@restart/hooks": "^0.4.9", + "@restart/ui": "^1.6.9", + "@types/react-transition-group": "^4.4.6", + "classnames": "^2.3.2", + "dom-helpers": "^5.2.1", + "invariant": "^2.2.4", + "prop-types": "^15.8.1", + "prop-types-extra": "^1.1.0", + "react-transition-group": "^4.4.5", + "uncontrollable": "^7.2.1", + "warning": "^4.0.3" }, - "bin": { - "resolve": "bin/resolve" + "peerDependencies": { + "@types/react": ">=16.14.8", + "react": ">=16.14.0", + "react-dom": ">=16.14.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "node_modules/react-chartjs-2": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.2.0.tgz", + "integrity": "sha512-98iN5aguJyVSxp5U3CblRLH67J8gkfyGNbiK3c+l1QI/G4irHMPQw44aEPmjVag+YKTyQ260NcF82GTQ3bdscA==", + "peerDependencies": { + "chart.js": "^4.1.1", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-datepicker": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-7.5.0.tgz", + "integrity": "sha512-6MzeamV8cWSOcduwePHfGqY40acuGlS1cG//ePHT6bVbLxWyqngaStenfH03n1wbzOibFggF66kWaBTb1SbTtQ==", "dependencies": { - "resolve-from": "^5.0.0" + "@floating-ui/react": "^0.26.23", + "clsx": "^2.1.1", + "date-fns": "^3.6.0", + "prop-types": "^15.8.1" }, - "engines": { - "node": ">=8" + "peerDependencies": { + "react": "^16.9.0 || ^17 || ^18", + "react-dom": "^16.9.0 || ^17 || ^18" } }, - "node_modules/resolve-cwd/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==", - "engines": { - "node": ">=8" + "node_modules/react-datepicker/node_modules/date-fns": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", + "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" } }, - "node_modules/resolve-dir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", - "dev": true, + "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": { - "expand-tilde": "^2.0.0", - "global-modules": "^1.0.0" + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" }, - "engines": { - "node": ">=0.10.0" + "peerDependencies": { + "react": "^18.3.1" } }, - "node_modules/resolve-dir/node_modules/global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", - "dev": true, + "node_modules/react-google-recaptcha": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/react-google-recaptcha/-/react-google-recaptcha-3.1.0.tgz", + "integrity": "sha512-cYW2/DWas8nEKZGD7SCu9BSuVz8iOcOLHChHyi7upUuVhkpkhYG/6N3KDiTQ3XAiZ2UAZkfvYKMfAHOzBOcGEg==", "dependencies": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" + "prop-types": "^15.5.0", + "react-async-script": "^1.2.0" }, - "engines": { - "node": ">=0.10.0" + "peerDependencies": { + "react": ">=16.4.1" } }, - "node_modules/resolve-dir/node_modules/global-prefix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", - "dev": true, + "node_modules/react-i18next": { + "version": "15.0.2", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.0.2.tgz", + "integrity": "sha512-z0W3/RES9Idv3MmJUcf0mDNeeMOUXe+xoL0kPfQPbDoZHmni/XsIoq5zgT2MCFUiau283GuBUK578uD/mkAbLQ==", "dependencies": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" + "@babel/runtime": "^7.25.0", + "html-parse-stringify": "^3.0.1" }, - "engines": { - "node": ">=0.10.0" + "peerDependencies": { + "i18next": ">= 23.2.3", + "react": ">= 16.8.0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } } }, - "node_modules/resolve-dir/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, + "node_modules/react-icons": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.2.1.tgz", + "integrity": "sha512-zdbW5GstTzXaVKvGSyTaBalt7HSfuK5ovrzlpyiWHAFXndXTdd/1hdDHI4xBM1Mn7YriT6aqESucFl9kEXzrdw==", + "peerDependencies": { + "react": "*" + } + }, + "node_modules/react-infinite-scroll-component": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/react-infinite-scroll-component/-/react-infinite-scroll-component-6.1.0.tgz", + "integrity": "sha512-SQu5nCqy8DxQWpnUVLx7V7b7LcA37aM7tvoWjTLZp1dk6EJibM5/4EJKzOnl07/BsM1Y40sKLuqjCwwH/xV0TQ==", "dependencies": { - "isexe": "^2.0.0" + "throttle-debounce": "^2.1.0" }, - "bin": { - "which": "bin/which" + "peerDependencies": { + "react": ">=16.0.0" } }, - "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/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==" }, - "node_modules/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/react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + }, + "node_modules/react-multi-carousel": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/react-multi-carousel/-/react-multi-carousel-2.8.5.tgz", + "integrity": "sha512-C5DAvJkfzR2JK9YixZ3oyF9x6R4LW6nzTpIXrl9Oujxi4uqP9SzVVCjl+JLM3tSdqdjAx/oWZK3dTVBSR73Q+w==", + "engines": { + "node": ">=8" } }, - "node_modules/resolve-url-loader": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-4.0.0.tgz", - "integrity": "sha512-05VEMczVREcbtT7Bz+C+96eUO5HDNvdthIiMB34t7FcF8ehcu4wC0sSgPUubs3XW2Q3CNLJk/BJrCU9wVRymiA==", + "node_modules/react-redux": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.1.2.tgz", + "integrity": "sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w==", "dependencies": { - "adjust-sourcemap-loader": "^4.0.0", - "convert-source-map": "^1.7.0", - "loader-utils": "^2.0.0", - "postcss": "^7.0.35", - "source-map": "0.6.1" - }, - "engines": { - "node": ">=8.9" + "@types/use-sync-external-store": "^0.0.3", + "use-sync-external-store": "^1.0.0" }, "peerDependencies": { - "rework": "1.0.1", - "rework-visit": "1.0.0" + "@types/react": "^18.2.25", + "react": "^18.0", + "redux": "^5.0.0" }, "peerDependenciesMeta": { - "rework": { + "@types/react": { "optional": true }, - "rework-visit": { + "redux": { "optional": true } } }, - "node_modules/resolve-url-loader/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==", + "node_modules/react-router": { + "version": "6.27.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.27.0.tgz", + "integrity": "sha512-YA+HGZXz4jaAkVoYBE98VQl+nVzI+cVI2Oj/06F5ZM+0u3TgedN9Y9kmMRo2mnkSK2nCpNQn0DVob4HCsY/WLw==", + "license": "MIT", "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" + "@remix-run/router": "1.20.0" }, "engines": { - "node": ">=8.9.0" + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" } }, - "node_modules/resolve-url-loader/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/resolve-url-loader/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "node_modules/react-router-dom": { + "version": "6.27.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.27.0.tgz", + "integrity": "sha512-+bvtFWMC0DgAFrfKXKG9Fc+BcXWRUO1aJIihbB79xaeq0v5UzfvnM5houGUm1Y461WVRcgAQ+Clh5rdb1eCx4g==", + "license": "MIT", "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" + "@remix-run/router": "1.20.0", + "react-router": "6.27.0" }, "engines": { - "node": ">=6.0.0" + "node": ">=14.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" } }, - "node_modules/resolve-url-loader/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==", - "engines": { - "node": ">=0.10.0" + "node_modules/react-toastify": { + "version": "10.0.6", + "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-10.0.6.tgz", + "integrity": "sha512-yYjp+omCDf9lhZcrZHKbSq7YMuK0zcYkDFTzfRFgTXkTFHZ1ToxwAonzA4JI5CxA91JpjFLmwEsZEgfYfOqI1A==", + "license": "MIT", + "dependencies": { + "clsx": "^2.1.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" } }, - "node_modules/resolve.exports": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.1.tgz", - "integrity": "sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ==", - "engines": { - "node": ">=10" + "node_modules/react-tooltip": { + "version": "5.28.0", + "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-5.28.0.tgz", + "integrity": "sha512-R5cO3JPPXk6FRbBHMO0rI9nkUG/JKfalBSQfZedZYzmqaZQgq7GLzF8vcCWx6IhUCKg0yPqJhXIzmIO5ff15xg==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.6.1", + "classnames": "^2.3.0" + }, + "peerDependencies": { + "react": ">=16.14.0", + "react-dom": ">=16.14.0" } }, - "node_modules/response-iterator": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/response-iterator/-/response-iterator-0.2.6.tgz", - "integrity": "sha512-pVzEEzrsg23Sh053rmDUvLSkGXluZio0qu8VT6ukrYuvtjVfCbDZH9d6PGXb8HZfzdNZt8feXv/jvUzlhRgLnw==", - "engines": { - "node": ">=0.8" + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" } }, - "node_modules/responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==", + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", "dev": true, "dependencies": { - "lowercase-keys": "^1.0.0" + "pify": "^2.3.0" } }, - "node_modules/restore-cursor": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", - "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", - "dev": true, + "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==", "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 6" } }, - "node_modules/restructure": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/restructure/-/restructure-3.0.0.tgz", - "integrity": "sha512-Xj8/MEIhhfj9X2rmD9iJ4Gga9EFqVlpMj3vfLnV2r/Mh5jRMryNV+6lWh9GdJtDBcBSPIqzRdfBQ3wDtNFv/uw==" - }, - "node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "optional": true, - "peer": true, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "devOptional": true, + "dependencies": { + "picomatch": "^2.2.1" + }, "engines": { - "node": ">= 4" + "node": ">=8.10.0" } }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "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": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/rfdc": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.1.tgz", - "integrity": "sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==", - "dev": true + "node_modules/redux": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==" }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "node_modules/redux-thunk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", + "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", + "peerDependencies": { + "redux": "^5.0.0" + } + }, + "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": { - "glob": "^7.1.3" + "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" }, - "bin": { - "rimraf": "bin.js" + "engines": { + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/robust-predicates": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", - "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==" + "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 }, - "node_modules/rollup": { - "version": "2.79.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", - "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", - "bin": { - "rollup": "dist/bin/rollup" + "node_modules/regenerate-unicode-properties": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", + "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2" }, "engines": { - "node": ">=10.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "node": ">=4" } }, - "node_modules/rollup-plugin-terser": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", - "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", - "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-terser", + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dev": true, "dependencies": { - "@babel/code-frame": "^7.10.4", - "jest-worker": "^26.2.1", - "serialize-javascript": "^4.0.0", - "terser": "^5.0.0" - }, - "peerDependencies": { - "rollup": "^2.0.0" + "@babel/runtime": "^7.8.4" } }, - "node_modules/rollup-plugin-terser/node_modules/jest-worker": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", - "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "node_modules/regex": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/regex/-/regex-4.3.2.tgz", + "integrity": "sha512-kK/AA3A9K6q2js89+VMymcboLOlF5lZRCYJv3gzszXFHBr6kO6qLGzbm+UIugBEV8SMMKCTR59txoY6ctRHYVw==" + }, + "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": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/rollup-plugin-terser/node_modules/serialize-javascript": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", - "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "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==", + "dev": true, "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "@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": ">=0.12.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==", - "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": ">=4" } }, - "node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "node_modules/registry-auth-token": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.2.tgz", + "integrity": "sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==", + "dev": true, "dependencies": { - "tslib": "^2.1.0" + "rc": "1.2.8" + }, + "engines": { + "node": ">=6.0.0" } }, - "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==", + "node_modules/registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "dev": true, "dependencies": { - "call-bind": "^1.0.7", - "get-intrinsic": "^1.2.4", - "has-symbols": "^1.0.3", - "isarray": "^2.0.5" + "rc": "^1.2.8" }, "engines": { - "node": ">=0.4" + "node": ">=8" + } + }, + "node_modules/regjsparser": { + "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" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "bin": { + "regjsparser": "bin/parser" } }, - "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==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" + "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==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/rehackt": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/rehackt/-/rehackt-0.1.0.tgz", + "integrity": "sha512-7kRDOuLHB87D/JESKxQoRwv4DzbIdwkAGQ7p6QKGdVlY1IZheUnVhlk/4UZlNUVxdAXpyxikE3URsG067ybVzw==", + "peerDependencies": { + "@types/react": "*", + "react": "*" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true }, - { - "type": "consulting", - "url": "https://feross.org/support" + "react": { + "optional": true } - ] + } }, - "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==", + "node_modules/remarkable": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/remarkable/-/remarkable-1.7.4.tgz", + "integrity": "sha512-e6NKUXgX95whv7IgddywbeN/ItCkWbISmc2DiqHJb0wTrqZIexqdco5b8Z3XZoo/48IdNVKM9ZCvTPJ4F5uvhg==", "dependencies": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", - "is-regex": "^1.1.4" + "argparse": "^1.0.10", + "autolinker": "~0.28.0" }, - "engines": { - "node": ">= 0.4" + "bin": { + "remarkable": "bin/remarkable.js" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">= 0.10.0" } }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "node_modules/repeat-element": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/sanitize-html": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.13.0.tgz", - "integrity": "sha512-Xff91Z+4Mz5QiNSLdLWwjgBDm5b1RU6xBT0+12rapjiaR7SwfRdjw8f+6Rir2MXKLrDicRFHdb51hGOAxmsUIA==", - "dependencies": { - "deepmerge": "^4.2.2", - "escape-string-regexp": "^4.0.0", - "htmlparser2": "^8.0.0", - "is-plain-object": "^5.0.0", - "parse-srcset": "^1.0.2", - "postcss": "^8.3.11" + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "engines": { + "node": ">=0.10" } }, - "node_modules/sanitize-html/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==", + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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/sanitize.css": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-13.0.0.tgz", - "integrity": "sha512-ZRwKbh/eQ6w9vmTjkuG0Ioi3HBwPFce0O+v//ve+aOq1oeCy7jMV2qzzAlpsNuqpqCBjjriM1lbtZbF/Q8jVyA==" + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, + "node_modules/reselect": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", + "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==" }, - "node_modules/sass": { - "version": "1.77.4", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.4.tgz", - "integrity": "sha512-vcF3Ckow6g939GMA4PeU7b2K/9FALXk2KF9J87txdHzXbUF9XRQRwSxcAs/fGaTnJeBFd7UoV22j3lzMLdM0Pw==", - "devOptional": true, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dependencies": { - "chokidar": ">=3.0.0 <4.0.0", - "immutable": "^4.0.0", - "source-map-js": ">=0.6.2 <2.0.0" + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { - "sass": "sass.js" + "resolve": "bin/resolve" }, - "engines": { - "node": ">=14.0.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/sass-graph": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-4.0.1.tgz", - "integrity": "sha512-5YCfmGBmxoIRYHnKK2AKzrAkCoQ8ozO+iumT8K4tXJXRVCPf+7s1/9KxTSW3Rbvf+7Y7b4FR3mWyLnQr3PHocA==", - "optional": true, - "peer": true, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, "dependencies": { - "glob": "^7.0.0", - "lodash": "^4.17.11", - "scss-tokenizer": "^0.4.3", - "yargs": "^17.2.1" - }, - "bin": { - "sassgraph": "bin/sassgraph" + "resolve-from": "^5.0.0" }, "engines": { - "node": ">=12" + "node": ">=8" } }, - "node_modules/sass-graph/node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "optional": true, - "peer": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, + "node_modules/resolve-cwd/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": ">=12" + "node": ">=8" } }, - "node_modules/sass-graph/node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "optional": true, - "peer": true, + "node_modules/resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", + "dev": true, "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" }, "engines": { - "node": ">=12" + "node": ">=0.10.0" } }, - "node_modules/sass-graph/node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "optional": true, - "peer": true, + "node_modules/resolve-dir/node_modules/global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "dependencies": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + }, "engines": { - "node": ">=12" + "node": ">=0.10.0" } }, - "node_modules/sass-loader": { - "version": "12.6.0", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.6.0.tgz", - "integrity": "sha512-oLTaH0YCtX4cfnJZxKSLAyglED0naiYfNG1iXfU5w1LNZ+ukoA5DtyDIN5zmKVZwYNJP4KRc5Y3hkWga+7tYfA==", + "node_modules/resolve-dir/node_modules/global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", + "dev": true, "dependencies": { - "klona": "^2.0.4", - "neo-async": "^2.6.2" + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" }, "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "fibers": ">= 3.1.0", - "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0", - "sass": "^1.3.0", - "sass-embedded": "*", - "webpack": "^5.0.0" + "node": ">=0.10.0" + } + }, + "node_modules/resolve-dir/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" }, - "peerDependenciesMeta": { - "fibers": { - "optional": true - }, - "node-sass": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - } + "bin": { + "which": "bin/which" } }, - "node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + "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/saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", - "dependencies": { - "xmlchars": "^2.2.0" - }, + "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/resolve.exports": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.1.tgz", + "integrity": "sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ==", + "dev": true, "engines": { "node": ">=10" } }, - "node_modules/scheduler": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", - "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", + "node_modules/response-iterator": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/response-iterator/-/response-iterator-0.2.6.tgz", + "integrity": "sha512-pVzEEzrsg23Sh053rmDUvLSkGXluZio0qu8VT6ukrYuvtjVfCbDZH9d6PGXb8HZfzdNZt8feXv/jvUzlhRgLnw==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==", + "dev": true, "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" + "lowercase-keys": "^1.0.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==", + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" }, "engines": { - "node": ">= 10.13.0" + "node": ">=18" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/schema-utils/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "node_modules/restore-cursor/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "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" + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/schema-utils/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==", - "peerDependencies": { - "ajv": "^6.9.1" + "node_modules/restore-cursor/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/schema-utils/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==" - }, - "node_modules/scss-tokenizer": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.4.3.tgz", - "integrity": "sha512-raKLgf1LI5QMQnG+RxHz6oK0sL3x3I4FN2UDLqgLOGO8hodECNnNh5BXn7fAyBxrA8zVzdQizQ6XjNJQ+uBwMw==", - "optional": true, - "peer": true, - "dependencies": { - "js-base64": "^2.4.9", - "source-map": "^0.7.3" - } + "node_modules/restructure": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/restructure/-/restructure-3.0.0.tgz", + "integrity": "sha512-Xj8/MEIhhfj9X2rmD9iJ4Gga9EFqVlpMj3vfLnV2r/Mh5jRMryNV+6lWh9GdJtDBcBSPIqzRdfBQ3wDtNFv/uw==" }, - "node_modules/scss-tokenizer/node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", - "optional": true, - "peer": true, + "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": { - "node": ">= 8" + "iojs": ">=1.0.0", + "node": ">=0.10.0" } }, - "node_modules/select-hose": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==" + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true }, - "node_modules/selfsigned": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.1.1.tgz", - "integrity": "sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==", + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, "dependencies": { - "node-forge": "^1" + "glob": "^7.1.3" }, - "engines": { - "node": ">=10" + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "node_modules/robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==" + }, + "node_modules/rollup": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.21.3.tgz", + "integrity": "sha512-7sqRtBNnEbcBtMeRVc6VRsJMmpI+JU1z9VTvW8D4gXIYQFz0aLcsE6rRkyghZkLfEgUZgVvOG7A5CVz/VW5GIA==", "dependencies": { - "lru-cache": "^6.0.0" + "@types/estree": "1.0.5" }, "bin": { - "semver": "bin/semver.js" + "rollup": "dist/bin/rollup" }, "engines": { - "node": ">=10" + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.21.3", + "@rollup/rollup-android-arm64": "4.21.3", + "@rollup/rollup-darwin-arm64": "4.21.3", + "@rollup/rollup-darwin-x64": "4.21.3", + "@rollup/rollup-linux-arm-gnueabihf": "4.21.3", + "@rollup/rollup-linux-arm-musleabihf": "4.21.3", + "@rollup/rollup-linux-arm64-gnu": "4.21.3", + "@rollup/rollup-linux-arm64-musl": "4.21.3", + "@rollup/rollup-linux-powerpc64le-gnu": "4.21.3", + "@rollup/rollup-linux-riscv64-gnu": "4.21.3", + "@rollup/rollup-linux-s390x-gnu": "4.21.3", + "@rollup/rollup-linux-x64-gnu": "4.21.3", + "@rollup/rollup-linux-x64-musl": "4.21.3", + "@rollup/rollup-win32-arm64-msvc": "4.21.3", + "@rollup/rollup-win32-ia32-msvc": "4.21.3", + "@rollup/rollup-win32-x64-msvc": "4.21.3", + "fsevents": "~2.3.2" } }, - "node_modules/semver-diff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", - "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", - "dev": true, - "dependencies": { - "semver": "^6.3.0" - }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", "engines": { - "node": ">=8" + "node": ">=0.12.0" } }, - "node_modules/semver-diff/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "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, - "bin": { - "semver": "bin/semver.js" + "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/semver/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" + "tslib": "^2.1.0" } }, - "node_modules/semver/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "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": { - "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" + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" }, "engines": { - "node": ">= 0.8.0" + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } + "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==", + "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/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "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/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==" + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "node_modules/send/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==", + "node_modules/sanitize-html": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.13.0.tgz", + "integrity": "sha512-Xff91Z+4Mz5QiNSLdLWwjgBDm5b1RU6xBT0+12rapjiaR7SwfRdjw8f+6Rir2MXKLrDicRFHdb51hGOAxmsUIA==", "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" + "deepmerge": "^4.2.2", + "escape-string-regexp": "^4.0.0", + "htmlparser2": "^8.0.0", + "is-plain-object": "^5.0.0", + "parse-srcset": "^1.0.2", + "postcss": "^8.3.11" } }, - "node_modules/send/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "node_modules/sanitize-html/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==", "engines": { - "node": ">= 0.8" + "node": ">=0.10.0" } }, - "node_modules/serialize-javascript": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", - "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "node_modules/sass": { + "version": "1.77.8", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.8.tgz", + "integrity": "sha512-4UHg6prsrycW20fqLGPShtEvo/WyHRVRHwOP4DzkUrObWoWI05QBSfzU71TVB7PFaL104TwNaHpjlWXAZbQiNQ==", + "devOptional": true, "dependencies": { - "randombytes": "^2.1.0" + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" } }, - "node_modules/serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "node_modules/saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "dev": true, "dependencies": { - "accepts": "~1.3.4", - "batch": "0.6.1", - "debug": "2.6.9", - "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" + "xmlchars": "^2.2.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">=10" } }, - "node_modules/serve-index/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "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": { - "ms": "2.0.0" - } - }, - "node_modules/serve-index/node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", - "engines": { - "node": ">= 0.6" + "loose-envify": "^1.1.0" } }, - "node_modules/serve-index/node_modules/http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" + "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, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">= 0.6" + "node": ">=10" } }, - "node_modules/serve-index/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" - }, - "node_modules/serve-index/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/serve-index/node_modules/setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" - }, - "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==", + "node_modules/semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "dev": true, "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" + "semver": "^6.3.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">=8" } }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "optional": true, - "peer": true + "node_modules/semver-diff/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/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", @@ -22152,6 +19988,7 @@ "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", @@ -22173,15 +20010,11 @@ "node": ">=0.10.0" } }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, "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" }, @@ -22193,34 +20026,29 @@ "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/shell-quote": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", - "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/shiki": { - "version": "0.14.7", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.7.tgz", - "integrity": "sha512-dNPAPrxSc87ua2sKJ3H5dQ/6ZaY8RNnaAqK+t0eG7p0Soi2ydiqbGOTaZCqaYvA/uZYfS1LJnemt3Q+mSfcPCg==", - "peer": true, + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.17.6.tgz", + "integrity": "sha512-RejGugKpDM75vh6YtF9R771acxHRDikC/01kxsUGW+Pnaz3pTY+c8aZB5CnD7p0vuFPs1HaoAIU/4E+NCfS+mQ==", "dependencies": { - "ansi-sequence-parser": "^1.1.0", - "jsonc-parser": "^3.2.0", - "vscode-oniguruma": "^1.7.0", - "vscode-textmate": "^8.0.0" + "@shikijs/core": "1.17.6", + "@shikijs/engine-javascript": "1.17.6", + "@shikijs/engine-oniguruma": "1.17.6", + "@shikijs/types": "1.17.6", + "@shikijs/vscode-textmate": "^9.2.2", + "@types/hast": "^3.0.4" } }, "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", @@ -22239,6 +20067,21 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "license": "MIT" + }, "node_modules/sirv": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.3.tgz", @@ -22256,12 +20099,14 @@ "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + "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" } @@ -22306,47 +20151,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "optional": true, - "peer": true, - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/sockjs": { - "version": "0.3.24", - "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", - "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", - "dependencies": { - "faye-websocket": "^0.11.3", - "uuid": "^8.3.2", - "websocket-driver": "^0.7.4" - } - }, - "node_modules/socks": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", - "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", - "optional": true, - "peer": true, + "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==", + "dev": true, "dependencies": { - "ip": "^2.0.0", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.13.0", - "npm": ">= 3.0.0" + "dot-case": "^3.0.4", + "tslib": "^2.0.3" } }, - "node_modules/source-list-map": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", - "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==" - }, "node_modules/source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -22356,37 +20170,18 @@ } }, "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "engines": { "node": ">=0.10.0" } }, - "node_modules/source-map-loader": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-3.0.2.tgz", - "integrity": "sha512-BokxPoLjyl3iOrgkWaakaxqnelAJSS+0V+De0kKIq6lyWrXuiPgYTGp6z3iHmqljKAaLXwZa+ctD8GccRJeVvg==", - "dependencies": { - "abab": "^2.0.5", - "iconv-lite": "^0.6.3", - "source-map-js": "^1.0.1" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.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==", + "devOptional": true, "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -22396,78 +20191,18 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "devOptional": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "deprecated": "Please use @jridgewell/sourcemap-codec instead" - }, - "node_modules/spdx-correct": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", - "optional": true, - "peer": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "optional": true, - "peer": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "optional": true, - "peer": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.13", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", - "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==", - "optional": true, - "peer": true - }, - "node_modules/spdy": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", - "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", - "dependencies": { - "debug": "^4.1.0", - "handle-thing": "^2.0.0", - "http-deceiver": "^1.2.7", - "select-hose": "^2.0.0", - "spdy-transport": "^3.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/spdy-transport": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", - "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", - "dependencies": { - "debug": "^4.1.0", - "detect-node": "^2.0.4", - "hpack.js": "^2.1.6", - "obuf": "^1.1.2", - "readable-stream": "^3.0.6", - "wbuf": "^1.7.3" + "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==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, "node_modules/sprintf-js": { @@ -22475,42 +20210,11 @@ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" }, - "node_modules/sshpk": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", - "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", - "optional": true, - "peer": true, - "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/stable": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", - "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", - "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility" - }, "node_modules/stack-utils": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, "dependencies": { "escape-string-regexp": "^2.0.0" }, @@ -22522,73 +20226,20 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, "engines": { "node": ">=8" } }, - "node_modules/stackframe": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", - "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==" - }, "node_modules/statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, "engines": { "node": ">= 0.6" } }, - "node_modules/stdout-stream": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz", - "integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==", - "optional": true, - "peer": true, - "dependencies": { - "readable-stream": "^2.0.1" - } - }, - "node_modules/stdout-stream/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "optional": true, - "peer": true - }, - "node_modules/stdout-stream/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "optional": true, - "peer": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/stdout-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "optional": true, - "peer": true - }, - "node_modules/stdout-stream/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "optional": true, - "peer": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -22616,18 +20267,14 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, "dependencies": { "char-regex": "^1.0.2", "strip-ansi": "^6.0.0" }, "engines": { "node": ">=10" - } - }, - "node_modules/string-natural-compare": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/string-natural-compare/-/string-natural-compare-3.0.1.tgz", - "integrity": "sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==" + } }, "node_modules/string-width": { "version": "4.2.3", @@ -22651,6 +20298,7 @@ "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", @@ -22672,10 +20320,21 @@ "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", @@ -22693,6 +20352,7 @@ "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", @@ -22703,37 +20363,33 @@ } }, "node_modules/string.prototype.trimstart": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", - "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", + "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.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "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/stringify-object": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", - "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", "dependencies": { - "get-own-enumerable-property-symbols": "^3.0.0", - "is-obj": "^1.0.1", - "is-regexp": "^1.0.0" + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" }, - "engines": { - "node": ">=4" - } - }, - "node_modules/stringify-object/node_modules/is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, "node_modules/strip-ansi": { @@ -22751,6 +20407,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, "engines": { "node": ">=8" } @@ -22763,18 +20420,11 @@ "node": ">=0.10.0" } }, - "node_modules/strip-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-2.0.1.tgz", - "integrity": "sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==", - "engines": { - "node": ">=10" - } - }, "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" } @@ -22783,7 +20433,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "devOptional": true, + "dev": true, "dependencies": { "min-indent": "^1.0.0" }, @@ -22795,6 +20445,7 @@ "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" }, @@ -22802,89 +20453,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/style-loader": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.3.tgz", - "integrity": "sha512-53BiGLXAcll9maCYtZi2RCQZKa8NQQai5C4horqKyRmHj9H7QmcUyucrH+4KW/gBQbXM2AsB0axoEcFZPlfPcw==", - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - } - }, - "node_modules/stylehacks": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", - "integrity": "sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==", - "dependencies": { - "browserslist": "^4.21.4", - "postcss-selector-parser": "^6.0.4" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } + "node_modules/strnum": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", + "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", + "license": "MIT", + "peer": true }, "node_modules/stylis": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" }, - "node_modules/sucrase": { - "version": "3.33.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.33.0.tgz", - "integrity": "sha512-ARGC7vbufOHfpvyGcZZXFaXCMZ9A4fffOGC5ucOW7+WHDGlAe8LJdf3Jts1sWhDeiI1RSWrKy5Hodl+JWGdW2A==", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "glob": "7.1.6", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "ts-interface-checker": "^0.1.9" - }, - "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/sucrase/node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "engines": { - "node": ">= 6" - } - }, - "node_modules/sucrase/node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -22900,6 +20480,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", + "dev": true, "dependencies": { "has-flag": "^4.0.0", "supports-color": "^7.0.0" @@ -22922,109 +20503,8 @@ "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": "1.3.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", - "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", - "deprecated": "This SVGO version is no longer supported. Upgrade to v2.x.x.", - "dependencies": { - "chalk": "^2.4.1", - "coa": "^2.0.2", - "css-select": "^2.0.0", - "css-select-base-adapter": "^0.1.1", - "css-tree": "1.0.0-alpha.37", - "csso": "^4.0.2", - "js-yaml": "^3.13.1", - "mkdirp": "~0.5.1", - "object.values": "^1.1.0", - "sax": "~1.2.4", - "stable": "^0.1.8", - "unquote": "~1.1.1", - "util.promisify": "~1.0.0" - }, - "bin": { - "svgo": "bin/svgo" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/svgo/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/svgo/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/svgo/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/svgo/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/svgo/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/svgo/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/svgo/node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/svgo/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" - } + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", + "dev": true }, "node_modules/symbol-observable": { "version": "4.0.0", @@ -23037,12 +20517,13 @@ "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true }, "node_modules/synckit": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", - "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.1.tgz", + "integrity": "sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==", "dev": true, "dependencies": { "@pkgr/core": "^0.1.0", @@ -23052,155 +20533,19 @@ "node": "^14.18.0 || >=16.0.0" }, "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/tailwindcss": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.3.tgz", - "integrity": "sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w==", - "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "arg": "^5.0.2", - "chokidar": "^3.5.3", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.2.12", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "jiti": "^1.18.2", - "lilconfig": "^2.1.0", - "micromatch": "^4.0.5", - "normalize-path": "^3.0.0", - "object-hash": "^3.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.4.23", - "postcss-import": "^15.1.0", - "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.1", - "postcss-nested": "^6.0.1", - "postcss-selector-parser": "^6.0.11", - "resolve": "^1.22.2", - "sucrase": "^3.32.0" - }, - "bin": { - "tailwind": "lib/cli.js", - "tailwindcss": "lib/cli.js" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/tailwindcss/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==", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/tailwindcss/node_modules/postcss-import": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", - "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", - "dependencies": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "postcss": "^8.0.0" - } - }, - "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/tar": { - "version": "6.1.15", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.15.tgz", - "integrity": "sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A==", - "optional": true, - "peer": 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==", - "optional": true, - "peer": 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==", - "optional": true, - "peer": true - }, - "node_modules/temp-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", - "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/tempy": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tempy/-/tempy-0.6.0.tgz", - "integrity": "sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==", - "dependencies": { - "is-stream": "^2.0.0", - "temp-dir": "^2.0.0", - "type-fest": "^0.16.0", - "unique-string": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tempy/node_modules/type-fest": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", - "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/unts" } }, + "node_modules/tabbable": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", + "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==" + }, "node_modules/terminal-link": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "dev": true, "dependencies": { "ansi-escapes": "^4.2.1", "supports-hyperlinks": "^2.0.0" @@ -23213,9 +20558,11 @@ } }, "node_modules/terser": { - "version": "5.19.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.19.0.tgz", - "integrity": "sha512-JpcpGOQLOXm2jsomozdMDpd5f8ZHh1rR48OFgWUH3QsyZcfPgv2qDCYbcDEAYNd4OZRj2bWYKpwdll/udZCk/Q==", + "version": "5.32.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.32.0.tgz", + "integrity": "sha512-v3Gtw3IzpBJ0ugkxEX8U0W6+TnPKRRCWGh1jC/iM/e3Ki5+qvO1L1EAZ56bZasc64aXHwRHNIQEzm6//i5cemQ==", + "optional": true, + "peer": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -23229,48 +20576,18 @@ "node": ">=10" } }, - "node_modules/terser-webpack-plugin": { - "version": "5.3.9", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz", - "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.17", - "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.1", - "terser": "^5.16.8" - }, - "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/terser/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==" + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "optional": true, + "peer": true }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", @@ -23291,31 +20608,15 @@ "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==" - }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dependencies": { - "any-promise": "^1.0.0" - } - }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, - "engines": { - "node": ">=0.8" - } + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "peer": true }, "node_modules/throat": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.2.tgz", - "integrity": "sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==" + "integrity": "sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==", + "dev": true }, "node_modules/throttle-debounce": { "version": "2.3.0", @@ -23371,16 +20672,16 @@ "safe-buffer": "~5.1.0" } }, - "node_modules/thunky": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" - }, "node_modules/tiny-inflate": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==" }, + "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==" + }, "node_modules/tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -23411,7 +20712,8 @@ "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==" + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true }, "node_modules/to-fast-properties": { "version": "2.0.0", @@ -23456,6 +20758,7 @@ "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==", + "devOptional": true, "dependencies": { "is-number": "^7.0.0" }, @@ -23463,14 +20766,6 @@ "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==", - "engines": { - "node": ">=0.6" - } - }, "node_modules/toml": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/toml/-/toml-2.3.6.tgz", @@ -23489,6 +20784,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", + "dev": true, "dependencies": { "psl": "^1.1.33", "punycode": "^2.1.1", @@ -23503,6 +20799,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, "engines": { "node": ">= 4.0.0" } @@ -23511,6 +20808,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "dev": true, "dependencies": { "punycode": "^2.1.1" }, @@ -23518,36 +20816,28 @@ "node": ">=8" } }, - "node_modules/trim-newlines": { + "node_modules/trim-lines": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", - "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", - "optional": true, - "peer": true, - "engines": { - "node": ">=8" + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/true-case-path": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz", - "integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==", - "optional": true, - "peer": true, - "dependencies": { - "glob": "^7.1.2" + "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, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" } }, - "node_modules/tryer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz", - "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==" - }, - "node_modules/ts-interface-checker": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" - }, "node_modules/ts-invariant": { "version": "0.10.3", "resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.10.3.tgz", @@ -23563,6 +20853,7 @@ "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", @@ -23574,6 +20865,7 @@ "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" }, @@ -23585,6 +20877,7 @@ "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" } @@ -23594,32 +20887,13 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "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==" - }, "node_modules/tsx": { - "version": "4.15.5", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.15.5.tgz", - "integrity": "sha512-iKi8jQ2VBmZ2kU/FkGkL2OSHBHsazsUzsdC/W/RwhKIEsIoZ1alCclZHP5jGfNHEaEWUJFM1GquzCf+4db3b0w==", + "version": "4.19.1", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.1.tgz", + "integrity": "sha512-0flMz1lh74BR4wOvBjuh9olbnwqCPc35OOlfyzHba0Dc+QNUeWX/Gq2YTbnwcWPO3BMd8fkzRVrHcsR+a7z7rA==", "dev": true, "dependencies": { - "esbuild": "~0.21.4", + "esbuild": "~0.23.0", "get-tsconfig": "^4.7.5" }, "bin": { @@ -23632,30 +20906,67 @@ "fsevents": "~2.3.3" } }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "node_modules/tsx/node_modules/@esbuild/win32-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.1.tgz", + "integrity": "sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==", + "cpu": [ + "x64" + ], + "dev": true, "optional": true, - "peer": true, - "dependencies": { - "safe-buffer": "^5.0.1" - }, + "os": [ + "win32" + ], "engines": { - "node": "*" + "node": ">=18" } }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "optional": true, - "peer": true + "node_modules/tsx/node_modules/esbuild": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.1.tgz", + "integrity": "sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.23.1", + "@esbuild/android-arm": "0.23.1", + "@esbuild/android-arm64": "0.23.1", + "@esbuild/android-x64": "0.23.1", + "@esbuild/darwin-arm64": "0.23.1", + "@esbuild/darwin-x64": "0.23.1", + "@esbuild/freebsd-arm64": "0.23.1", + "@esbuild/freebsd-x64": "0.23.1", + "@esbuild/linux-arm": "0.23.1", + "@esbuild/linux-arm64": "0.23.1", + "@esbuild/linux-ia32": "0.23.1", + "@esbuild/linux-loong64": "0.23.1", + "@esbuild/linux-mips64el": "0.23.1", + "@esbuild/linux-ppc64": "0.23.1", + "@esbuild/linux-riscv64": "0.23.1", + "@esbuild/linux-s390x": "0.23.1", + "@esbuild/linux-x64": "0.23.1", + "@esbuild/netbsd-x64": "0.23.1", + "@esbuild/openbsd-arm64": "0.23.1", + "@esbuild/openbsd-x64": "0.23.1", + "@esbuild/sunos-x64": "0.23.1", + "@esbuild/win32-arm64": "0.23.1", + "@esbuild/win32-ia32": "0.23.1", + "@esbuild/win32-x64": "0.23.1" + } }, "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, + "peer": true, "dependencies": { "prelude-ls": "^1.2.1" }, @@ -23667,6 +20978,7 @@ "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" } @@ -23682,22 +20994,11 @@ "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==", - "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", @@ -23711,6 +21012,7 @@ "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", @@ -23729,6 +21031,7 @@ "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", @@ -23748,6 +21051,7 @@ "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", @@ -23772,53 +21076,55 @@ "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, "dependencies": { "is-typedarray": "^1.0.0" } }, "node_modules/typedoc": { - "version": "0.25.7", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.25.7.tgz", - "integrity": "sha512-m6A6JjQRg39p2ZVRIN3NKXgrN8vzlHhOS+r9ymUYtcUP/TIQPvWSq7YgE5ZjASfv5Vd5BW5xrir6Gm2XNNcOow==", - "peer": true, + "version": "0.26.10", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.26.10.tgz", + "integrity": "sha512-xLmVKJ8S21t+JeuQLNueebEuTVphx6IrP06CdV7+0WVflUSW3SPmR+h1fnWVdAR/FQePEgsSWCUHXqKKjzuUAw==", "dependencies": { "lunr": "^2.3.9", - "marked": "^4.3.0", - "minimatch": "^9.0.3", - "shiki": "^0.14.7" + "markdown-it": "^14.1.0", + "minimatch": "^9.0.5", + "shiki": "^1.16.2", + "yaml": "^2.5.1" }, "bin": { "typedoc": "bin/typedoc" }, "engines": { - "node": ">= 16" + "node": ">= 18" }, "peerDependencies": { - "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x || 5.3.x" + "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x" } }, "node_modules/typedoc-plugin-markdown": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/typedoc-plugin-markdown/-/typedoc-plugin-markdown-4.0.3.tgz", - "integrity": "sha512-0tZbeVGGCd4+lpoIX+yHWgUfyaLZCQCgJOpuVdTtOtD3+jKaedJ4sl/tkNaYBPeWVKiyDkSHfGuHkq53jlzIFg==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/typedoc-plugin-markdown/-/typedoc-plugin-markdown-4.2.1.tgz", + "integrity": "sha512-7hQt/1WaW/VI4+x3sxwcCGsEylP1E1GvF6OTTELK5sfTEp6AeK+83jkCOgZGp1pI2DiOammMYQMnxxOny9TKsQ==", + "engines": { + "node": ">= 18" + }, "peerDependencies": { - "typedoc": "0.25.x" + "typedoc": "0.26.x" } }, "node_modules/typedoc/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==", - "peer": true, "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/typedoc/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "peer": true, + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -23829,22 +21135,39 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/typedoc/node_modules/yaml": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.1.tgz", + "integrity": "sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=14.17" } }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==" + }, "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", @@ -23870,14 +21193,16 @@ } }, "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==" + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "devOptional": 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==", + "dev": true, "engines": { "node": ">=4" } @@ -23886,6 +21211,7 @@ "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" @@ -23898,6 +21224,7 @@ "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" } @@ -23915,6 +21242,7 @@ "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" } @@ -23937,6 +21265,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, "dependencies": { "crypto-random-string": "^2.0.0" }, @@ -23944,40 +21273,82 @@ "node": ">=8" } }, - "node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "engines": { - "node": ">= 10.0.0" + "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==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "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==", + "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==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, "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/unquote": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", - "integrity": "sha512-vRCqFv6UhXpWxZPyGDh/F3ZpNv8/qo7w6iufLpQg9aKnQ71qM4B5KiI7Mia9COcjEhrO9LueHpMYjYzsWH3OIg==" - }, - "node_modules/upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", - "engines": { - "node": ">=4", - "yarn": "*" - } - }, "node_modules/update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "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", @@ -23993,8 +21364,8 @@ } ], "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "escalade": "^3.1.2", + "picocolors": "^1.0.1" }, "bin": { "update-browserslist-db": "cli.js" @@ -24051,6 +21422,7 @@ "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" } @@ -24059,6 +21431,7 @@ "version": "1.5.10", "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, "dependencies": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" @@ -24076,58 +21449,41 @@ "node": ">=4" } }, + "node_modules/use-memo-one": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.3.tgz", + "integrity": "sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "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", + "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "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==" }, - "node_modules/util.promisify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz", - "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==", - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.2", - "has-symbols": "^1.0.1", - "object.getownpropertydescriptors": "^2.1.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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==" - }, "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/utrie": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz", - "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==", - "dependencies": { - "base64-arraybuffer": "^1.0.2" - } - }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, "node_modules/v8-to-istanbul": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", + "dev": true, "dependencies": { "@types/istanbul-lib-coverage": "^2.0.1", "convert-source-map": "^1.6.0", @@ -24137,404 +21493,497 @@ "node": ">=10.12.0" } }, - "node_modules/v8-to-istanbul/node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "optional": true, - "peer": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.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==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", - "engines": [ - "node >=0.6.0" - ], - "optional": true, - "peer": true, - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "node_modules/verror/node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", - "optional": true, - "peer": true - }, - "node_modules/void-elements": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", - "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "node_modules/v8-to-istanbul/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": ">=0.10.0" + "node": ">= 8" } }, - "node_modules/vscode-oniguruma": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", - "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==", - "peer": true - }, - "node_modules/vscode-textmate": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz", - "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", - "peer": true + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } }, - "node_modules/w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "deprecated": "Use your platform's native performance.now() and performance.timeOrigin.", + "node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", "dependencies": { - "browser-process-hrtime": "^1.0.0" + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/w3c-xmlserializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", - "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "node_modules/vite": { + "version": "5.4.8", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.8.tgz", + "integrity": "sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==", "dependencies": { - "xml-name-validator": "^3.0.0" + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" }, "engines": { - "node": ">=10" + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } } }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dependencies": { - "makeerror": "1.0.12" + "node_modules/vite-plugin-environment": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/vite-plugin-environment/-/vite-plugin-environment-1.1.3.tgz", + "integrity": "sha512-9LBhB0lx+2lXVBEWxFZC+WO7PKEyE/ykJ7EPWCq95NEcCpblxamTbs5Dm3DLBGzwODpJMEnzQywJU8fw6XGGGA==", + "peerDependencies": { + "vite": ">= 2.7" } }, - "node_modules/warning": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", - "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "node_modules/vite-plugin-svgr": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/vite-plugin-svgr/-/vite-plugin-svgr-4.2.0.tgz", + "integrity": "sha512-SC7+FfVtNQk7So0XMjrrtLAbEC8qjFPifyD7+fs/E6aaNdVde6umlVVh0QuwDLdOMu7vp5RiGFsB70nj5yo0XA==", + "dev": true, "dependencies": { - "loose-envify": "^1.0.0" + "@rollup/pluginutils": "^5.0.5", + "@svgr/core": "^8.1.0", + "@svgr/plugin-jsx": "^8.1.0" + }, + "peerDependencies": { + "vite": "^2.6.0 || 3 || 4 || 5" } }, - "node_modules/watchpack": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", - "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "node_modules/vite-plugin-svgr/node_modules/@rollup/pluginutils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz", + "integrity": "sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==", + "dev": true, "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" }, "engines": { - "node": ">=10.13.0" + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } } }, - "node_modules/wbuf": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", - "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", - "dependencies": { - "minimalistic-assert": "^1.0.0" + "node_modules/vite-plugin-svgr/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" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.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==", - "dependencies": { - "defaults": "^1.0.3" + "node_modules/vite-plugin-svgr/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==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/web-vitals": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-1.1.2.tgz", - "integrity": "sha512-PFMKIY+bRSXlMxVAQ+m2aw9c/ioUYfDgrYot0YUa+/xa0sakubWhSDyxAKwzymvXVdF4CZI71g06W+mqhzu6ig==" + "node_modules/vite-plugin-svgr/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==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/webidl-conversions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "node_modules/vite-plugin-svgr/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==", + "dev": true, "engines": { - "node": ">=10.4" + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/webpack": { - "version": "5.88.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.1.tgz", - "integrity": "sha512-FROX3TxQnC/ox4N+3xQoWZzvGXSuscxR32rbzjpXgEzWudJFEJBpdlkkob2ylrv5yzzufD1zph1OoFsLtm6stQ==", - "dependencies": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^1.0.0", - "@webassemblyjs/ast": "^1.11.5", - "@webassemblyjs/wasm-edit": "^1.11.5", - "@webassemblyjs/wasm-parser": "^1.11.5", - "acorn": "^8.7.1", - "acorn-import-assertions": "^1.9.0", - "browserslist": "^4.14.5", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.15.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.9", - "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.7", - "watchpack": "^2.4.0", - "webpack-sources": "^3.2.3" + "node_modules/vite-plugin-svgr/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==", + "dev": true, + "engines": { + "node": ">=14" }, - "bin": { - "webpack": "bin/webpack.js" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/vite-plugin-svgr/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==", + "dev": true, "engines": { - "node": ">=10.13.0" + "node": ">=12" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "type": "github", + "url": "https://github.com/sponsors/gregberge" }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/webpack-dev-middleware": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", - "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "node_modules/vite-plugin-svgr/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==", + "dev": true, "dependencies": { - "colorette": "^2.0.10", - "memfs": "^3.4.3", - "mime-types": "^2.1.31", - "range-parser": "^1.2.1", - "schema-utils": "^4.0.0" + "@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": ">= 12.13.0" + "node": ">=14" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "type": "github", + "url": "https://github.com/sponsors/gregberge" }, "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" + "@babel/core": "^7.0.0-0" } }, - "node_modules/webpack-dev-middleware/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==", + "node_modules/vite-plugin-svgr/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==", + "dev": true, "dependencies": { - "fast-deep-equal": "^3.1.3" + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "camelcase": "^6.2.0", + "cosmiconfig": "^8.1.3", + "snake-case": "^3.0.4" }, - "peerDependencies": { - "ajv": "^8.8.2" + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" } }, - "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==", + "node_modules/vite-plugin-svgr/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==", + "dev": true, "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" + "@babel/types": "^7.21.3", + "entities": "^4.4.0" }, "engines": { - "node": ">= 12.13.0" + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/vite-plugin-svgr/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==", + "dev": true, + "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/vite-plugin-svgr/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 + }, + "node_modules/vite-plugin-svgr/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/webpack-dev-server": { - "version": "4.15.1", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz", - "integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==", - "dependencies": { - "@types/bonjour": "^3.5.9", - "@types/connect-history-api-fallback": "^1.3.5", - "@types/express": "^4.17.13", - "@types/serve-index": "^1.9.1", - "@types/serve-static": "^1.13.10", - "@types/sockjs": "^0.3.33", - "@types/ws": "^8.5.5", - "ansi-html-community": "^0.0.8", - "bonjour-service": "^1.0.11", - "chokidar": "^3.5.3", - "colorette": "^2.0.10", - "compression": "^1.7.4", - "connect-history-api-fallback": "^2.0.0", - "default-gateway": "^6.0.3", - "express": "^4.17.3", - "graceful-fs": "^4.2.6", - "html-entities": "^2.3.2", - "http-proxy-middleware": "^2.0.3", - "ipaddr.js": "^2.0.1", - "launch-editor": "^2.6.0", - "open": "^8.0.9", - "p-retry": "^4.5.0", - "rimraf": "^3.0.2", - "schema-utils": "^4.0.0", - "selfsigned": "^2.1.1", - "serve-index": "^1.9.1", - "sockjs": "^0.3.24", - "spdy": "^4.0.2", - "webpack-dev-middleware": "^5.3.1", - "ws": "^8.13.0" - }, - "bin": { - "webpack-dev-server": "bin/webpack-dev-server.js" + "node_modules/vite-plugin-svgr/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==", + "dev": true, + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" }, "engines": { - "node": ">= 12.13.0" + "node": ">=14" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "url": "https://github.com/sponsors/d-fischer" }, "peerDependencies": { - "webpack": "^4.37.0 || ^5.0.0" + "typescript": ">=4.9.5" }, "peerDependenciesMeta": { - "webpack": { - "optional": true - }, - "webpack-cli": { + "typescript": { "optional": true } } }, - "node_modules/webpack-dev-server/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==", + "node_modules/vite-plugin-svgr/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true + }, + "node_modules/vite-plugin-svgr/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==", + "dev": true, "dependencies": { - "fast-deep-equal": "^3.1.3" + "argparse": "^2.0.1" }, - "peerDependencies": { - "ajv": "^8.8.2" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/webpack-dev-server/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==", + "node_modules/vite-tsconfig-paths": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-5.0.1.tgz", + "integrity": "sha512-yqwv+LstU7NwPeNqajZzLEBVpUFU6Dugtb2P84FXuvaoYA+/70l9MHE+GYfYAycVyPSDYZ7mjOFuYBRqlEpTig==", "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" + "debug": "^4.1.1", + "globrex": "^0.1.2", + "tsconfck": "^3.0.3" }, - "engines": { - "node": ">= 12.13.0" + "peerDependencies": { + "vite": "*" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "peerDependenciesMeta": { + "vite": { + "optional": true + } } }, - "node_modules/webpack-manifest-plugin": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/webpack-manifest-plugin/-/webpack-manifest-plugin-4.1.1.tgz", - "integrity": "sha512-YXUAwxtfKIJIKkhg03MKuiFAD72PlrqCiwdwO4VEXdRO5V0ORCNwaOwAZawPZalCbmH9kBDmXnNeQOw+BIEiow==", - "dependencies": { - "tapable": "^2.0.0", - "webpack-sources": "^2.2.0" + "node_modules/vite-tsconfig-paths/node_modules/tsconfck": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.3.tgz", + "integrity": "sha512-ulNZP1SVpRDesxeMLON/LtWM8HIgAJEIVpVVhBM6gsmvQ8+Rh+ZG7FWGvHh7Ah3pRABwVJWklWCr/BTZSv0xnQ==", + "bin": { + "tsconfck": "bin/tsconfck.js" }, "engines": { - "node": ">=12.22.0" + "node": "^18 || >=20" }, "peerDependencies": { - "webpack": "^4.44.2 || ^5.47.0" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/webpack-manifest-plugin/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==", + "node_modules/void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", "engines": { "node": ">=0.10.0" } }, - "node_modules/webpack-manifest-plugin/node_modules/webpack-sources": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.3.1.tgz", - "integrity": "sha512-y9EI9AO42JjEcrTJFOYmVywVZdKVUfOvDUPsJea5GIr1JOEGFVqwlY2K098fFoIjOkDzHn2AjRvM8dsBZu+gCA==", + "node_modules/w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "deprecated": "Use your platform's native performance.now() and performance.timeOrigin.", + "dev": true, "dependencies": { - "source-list-map": "^2.0.1", - "source-map": "^0.6.1" + "browser-process-hrtime": "^1.0.0" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "dev": true, + "dependencies": { + "xml-name-validator": "^3.0.0" }, "engines": { - "node": ">=10.13.0" + "node": ">=10" } }, - "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==", - "engines": { - "node": ">=10.13.0" + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "dependencies": { + "makeerror": "1.0.12" } }, - "node_modules/websocket-driver": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", "dependencies": { - "http-parser-js": ">=0.5.1", - "safe-buffer": ">=5.1.0", - "websocket-extensions": ">=0.1.1" - }, - "engines": { - "node": ">=0.8.0" + "loose-envify": "^1.0.0" } }, - "node_modules/websocket-extensions": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/web-vitals": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-4.2.4.tgz", + "integrity": "sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==" + }, + "node_modules/webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "dev": true, "engines": { - "node": ">=0.8.0" + "node": ">=10.4" } }, "node_modules/whatwg-encoding": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dev": true, "dependencies": { "iconv-lite": "0.4.24" } @@ -24543,6 +21992,7 @@ "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" }, @@ -24551,19 +22001,22 @@ } }, "node_modules/whatwg-fetch": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz", - "integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==" + "version": "3.6.20", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", + "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==", + "dev": true }, "node_modules/whatwg-mimetype": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==" + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true }, "node_modules/whatwg-url": { "version": "8.7.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "dev": true, "dependencies": { "lodash": "^4.7.0", "tr46": "^2.1.0", @@ -24577,6 +22030,7 @@ "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" }, @@ -24591,6 +22045,7 @@ "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", @@ -24603,12 +22058,13 @@ } }, "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==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.4.tgz", + "integrity": "sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==", + "dev": true, "dependencies": { - "function.prototype.name": "^1.1.5", - "has-tostringtag": "^1.0.0", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", "is-async-function": "^2.0.0", "is-date-object": "^1.0.5", "is-finalizationregistry": "^1.0.2", @@ -24617,8 +22073,8 @@ "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" + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.15" }, "engines": { "node": ">= 0.4" @@ -24631,6 +22087,7 @@ "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", @@ -24648,6 +22105,7 @@ "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", @@ -24662,16 +22120,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "optional": true, - "peer": true, - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, "node_modules/widest-line": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", @@ -24684,269 +22132,11 @@ "node": ">=8" } }, - "node_modules/workbox-background-sync": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-6.6.0.tgz", - "integrity": "sha512-jkf4ZdgOJxC9u2vztxLuPT/UjlH7m/nWRQ/MgGL0v8BJHoZdVGJd18Kck+a0e55wGXdqyHO+4IQTk0685g4MUw==", - "dependencies": { - "idb": "^7.0.1", - "workbox-core": "6.6.0" - } - }, - "node_modules/workbox-broadcast-update": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-6.6.0.tgz", - "integrity": "sha512-nm+v6QmrIFaB/yokJmQ/93qIJ7n72NICxIwQwe5xsZiV2aI93MGGyEyzOzDPVz5THEr5rC3FJSsO3346cId64Q==", - "dependencies": { - "workbox-core": "6.6.0" - } - }, - "node_modules/workbox-build": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-6.6.0.tgz", - "integrity": "sha512-Tjf+gBwOTuGyZwMz2Nk/B13Fuyeo0Q84W++bebbVsfr9iLkDSo6j6PST8tET9HYA58mlRXwlMGpyWO8ETJiXdQ==", - "dependencies": { - "@apideck/better-ajv-errors": "^0.3.1", - "@babel/core": "^7.11.1", - "@babel/preset-env": "^7.11.0", - "@babel/runtime": "^7.11.2", - "@rollup/plugin-babel": "^5.2.0", - "@rollup/plugin-node-resolve": "^11.2.1", - "@rollup/plugin-replace": "^2.4.1", - "@surma/rollup-plugin-off-main-thread": "^2.2.3", - "ajv": "^8.6.0", - "common-tags": "^1.8.0", - "fast-json-stable-stringify": "^2.1.0", - "fs-extra": "^9.0.1", - "glob": "^7.1.6", - "lodash": "^4.17.20", - "pretty-bytes": "^5.3.0", - "rollup": "^2.43.1", - "rollup-plugin-terser": "^7.0.0", - "source-map": "^0.8.0-beta.0", - "stringify-object": "^3.3.0", - "strip-comments": "^2.0.1", - "tempy": "^0.6.0", - "upath": "^1.2.0", - "workbox-background-sync": "6.6.0", - "workbox-broadcast-update": "6.6.0", - "workbox-cacheable-response": "6.6.0", - "workbox-core": "6.6.0", - "workbox-expiration": "6.6.0", - "workbox-google-analytics": "6.6.0", - "workbox-navigation-preload": "6.6.0", - "workbox-precaching": "6.6.0", - "workbox-range-requests": "6.6.0", - "workbox-recipes": "6.6.0", - "workbox-routing": "6.6.0", - "workbox-strategies": "6.6.0", - "workbox-streams": "6.6.0", - "workbox-sw": "6.6.0", - "workbox-window": "6.6.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/workbox-build/node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/workbox-build/node_modules/source-map": { - "version": "0.8.0-beta.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", - "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", - "dependencies": { - "whatwg-url": "^7.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/workbox-build/node_modules/tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/workbox-build/node_modules/webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" - }, - "node_modules/workbox-build/node_modules/whatwg-url": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", - "dependencies": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - }, - "node_modules/workbox-cacheable-response": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-6.6.0.tgz", - "integrity": "sha512-JfhJUSQDwsF1Xv3EV1vWzSsCOZn4mQ38bWEBR3LdvOxSPgB65gAM6cS2CX8rkkKHRgiLrN7Wxoyu+TuH67kHrw==", - "deprecated": "workbox-background-sync@6.6.0", - "dependencies": { - "workbox-core": "6.6.0" - } - }, - "node_modules/workbox-core": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-6.6.0.tgz", - "integrity": "sha512-GDtFRF7Yg3DD859PMbPAYPeJyg5gJYXuBQAC+wyrWuuXgpfoOrIQIvFRZnQ7+czTIQjIr1DhLEGFzZanAT/3bQ==" - }, - "node_modules/workbox-expiration": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-6.6.0.tgz", - "integrity": "sha512-baplYXcDHbe8vAo7GYvyAmlS4f6998Jff513L4XvlzAOxcl8F620O91guoJ5EOf5qeXG4cGdNZHkkVAPouFCpw==", - "dependencies": { - "idb": "^7.0.1", - "workbox-core": "6.6.0" - } - }, - "node_modules/workbox-google-analytics": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-6.6.0.tgz", - "integrity": "sha512-p4DJa6OldXWd6M9zRl0H6vB9lkrmqYFkRQ2xEiNdBFp9U0LhsGO7hsBscVEyH9H2/3eZZt8c97NB2FD9U2NJ+Q==", - "dependencies": { - "workbox-background-sync": "6.6.0", - "workbox-core": "6.6.0", - "workbox-routing": "6.6.0", - "workbox-strategies": "6.6.0" - } - }, - "node_modules/workbox-navigation-preload": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-6.6.0.tgz", - "integrity": "sha512-utNEWG+uOfXdaZmvhshrh7KzhDu/1iMHyQOV6Aqup8Mm78D286ugu5k9MFD9SzBT5TcwgwSORVvInaXWbvKz9Q==", - "dependencies": { - "workbox-core": "6.6.0" - } - }, - "node_modules/workbox-precaching": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-6.6.0.tgz", - "integrity": "sha512-eYu/7MqtRZN1IDttl/UQcSZFkHP7dnvr/X3Vn6Iw6OsPMruQHiVjjomDFCNtd8k2RdjLs0xiz9nq+t3YVBcWPw==", - "dependencies": { - "workbox-core": "6.6.0", - "workbox-routing": "6.6.0", - "workbox-strategies": "6.6.0" - } - }, - "node_modules/workbox-range-requests": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-6.6.0.tgz", - "integrity": "sha512-V3aICz5fLGq5DpSYEU8LxeXvsT//mRWzKrfBOIxzIdQnV/Wj7R+LyJVTczi4CQ4NwKhAaBVaSujI1cEjXW+hTw==", - "dependencies": { - "workbox-core": "6.6.0" - } - }, - "node_modules/workbox-recipes": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-recipes/-/workbox-recipes-6.6.0.tgz", - "integrity": "sha512-TFi3kTgYw73t5tg73yPVqQC8QQjxJSeqjXRO4ouE/CeypmP2O/xqmB/ZFBBQazLTPxILUQ0b8aeh0IuxVn9a6A==", - "dependencies": { - "workbox-cacheable-response": "6.6.0", - "workbox-core": "6.6.0", - "workbox-expiration": "6.6.0", - "workbox-precaching": "6.6.0", - "workbox-routing": "6.6.0", - "workbox-strategies": "6.6.0" - } - }, - "node_modules/workbox-routing": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-6.6.0.tgz", - "integrity": "sha512-x8gdN7VDBiLC03izAZRfU+WKUXJnbqt6PG9Uh0XuPRzJPpZGLKce/FkOX95dWHRpOHWLEq8RXzjW0O+POSkKvw==", - "dependencies": { - "workbox-core": "6.6.0" - } - }, - "node_modules/workbox-strategies": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-6.6.0.tgz", - "integrity": "sha512-eC07XGuINAKUWDnZeIPdRdVja4JQtTuc35TZ8SwMb1ztjp7Ddq2CJ4yqLvWzFWGlYI7CG/YGqaETntTxBGdKgQ==", - "dependencies": { - "workbox-core": "6.6.0" - } - }, - "node_modules/workbox-streams": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-6.6.0.tgz", - "integrity": "sha512-rfMJLVvwuED09CnH1RnIep7L9+mj4ufkTyDPVaXPKlhi9+0czCu+SJggWCIFbPpJaAZmp2iyVGLqS3RUmY3fxg==", - "dependencies": { - "workbox-core": "6.6.0", - "workbox-routing": "6.6.0" - } - }, - "node_modules/workbox-sw": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-6.6.0.tgz", - "integrity": "sha512-R2IkwDokbtHUE4Kus8pKO5+VkPHD2oqTgl+XJwh4zbF1HyjAbgNmK/FneZHVU7p03XUt9ICfuGDYISWG9qV/CQ==" - }, - "node_modules/workbox-webpack-plugin": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-webpack-plugin/-/workbox-webpack-plugin-6.6.0.tgz", - "integrity": "sha512-xNZIZHalboZU66Wa7x1YkjIqEy1gTR+zPM+kjrYJzqN7iurYZBctBLISyScjhkJKYuRrZUP0iqViZTh8rS0+3A==", - "dependencies": { - "fast-json-stable-stringify": "^2.1.0", - "pretty-bytes": "^5.4.1", - "upath": "^1.2.0", - "webpack-sources": "^1.4.3", - "workbox-build": "6.6.0" - }, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "webpack": "^4.4.0 || ^5.9.0" - } - }, - "node_modules/workbox-webpack-plugin/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==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/workbox-webpack-plugin/node_modules/webpack-sources": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", - "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", - "dependencies": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" - } - }, - "node_modules/workbox-window": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/workbox-window/-/workbox-window-6.6.0.tgz", - "integrity": "sha512-L4N9+vka17d16geaJXXRjENLFldvkWy7JyGxElRD0JvBxvFEd8LOhr+uXCcar/NzAmIBRv9EZ+M+Qr4mOoBITw==", - "dependencies": { - "@types/trusted-types": "^2.0.2", - "workbox-core": "6.6.0" - } - }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -24962,12 +22152,14 @@ "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==" + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true }, "node_modules/write-file-atomic": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, "dependencies": { "imurmurhash": "^0.1.4", "is-typedarray": "^1.0.0", @@ -24976,9 +22168,10 @@ } }, "node_modules/ws": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "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" }, @@ -25007,12 +22200,14 @@ "node_modules/xml-name-validator": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==" + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true }, "node_modules/xmlchars": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true }, "node_modules/xtend": { "version": "4.0.2", @@ -25026,6 +22221,7 @@ "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, "engines": { "node": ">=10" } @@ -25047,6 +22243,7 @@ "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", @@ -25064,6 +22261,7 @@ "version": "20.2.9", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, "engines": { "node": ">=10" } @@ -25072,6 +22270,8 @@ "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, + "peer": true, "engines": { "node": ">=10" }, @@ -25096,9 +22296,19 @@ "version": "3.22.4", "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } } } } diff --git a/package.json b/package.json index 37537ffded..6f1ec40424 100644 --- a/package.json +++ b/package.json @@ -5,68 +5,77 @@ "type": "module", "config-overrides-path": "scripts/config-overrides", "dependencies": { - "@apollo/client": "^3.4.0-beta.19", + "@apollo/client": "^3.11.4", "@apollo/link-error": "^2.0.0-beta.3", "@apollo/react-testing": "^4.0.0", - "@dicebear/collection": "^8.0.1", - "@dicebear/core": "^8.0.1", - "@emotion/react": "^11.11.4", - "@emotion/styled": "^11.11.5", - "@mui/icons-material": "^5.8.3", - "@mui/material": "^5.15.20", + "@dicebear/collection": "^8.0.2", + "@dicebear/core": "^8.0.2", + "@emotion/react": "^11.13.3", + "@emotion/styled": "^11.13.0", + "@mui/icons-material": "^5.16.7", + "@mui/material": "^5.16.7", "@mui/private-theming": "^5.15.12", "@mui/system": "^5.14.12", - "@mui/x-charts": "^7.6.2", - "@mui/x-data-grid": "^6.20.0", - "@mui/x-date-pickers": "^7.6.1", - "@pdfme/generator": "^1.2.6", - "bootstrap": "^5.3.0", "chart.js": "^4.4.3", + "@mui/x-charts": "^7.17.0", + "@mui/x-data-grid": "^7.22.0", + "@mui/x-date-pickers": "^7.11.1", + "@pdfme/generator": "^4.5.2", + "@reduxjs/toolkit": "^2.3.0", + "@vitejs/plugin-react": "^4.3.2", + "babel-plugin-transform-import-meta": "^2.2.1", + "bootstrap": "^5.3.3", "customize-cra": "^1.0.0", - "dayjs": "^1.11.11", - "flag-icons": "^6.6.6", - "graphql": "^16.8.2", + "dayjs": "^1.11.13", + "dotenv": "^16.4.5", + "flag-icons": "^7.2.3", + "graphql": "^16.9.0", "graphql-tag": "^2.12.6", "graphql-ws": "^5.16.0", "history": "^5.3.0", - "html2canvas": "^1.4.1", - "i18next": "^21.8.14", + "i18next": "^23.15.1", "i18next-browser-languagedetector": "^8.0.0", - "i18next-http-backend": "^1.4.1", + "i18next-http-backend": "^2.6.1", "inquirer": "^8.0.0", "js-cookie": "^3.0.1", "markdown-toc": "^1.2.0", - "prettier": "^3.2.5", - "react": "^17.0.2", - "react-app-rewired": "^2.2.1", - "react-bootstrap": "^2.7.4", - "react-chartjs-2": "^5.2.0", - "react-datepicker": "^4.2.0", - "react-dom": "^17.0.2", - "react-google-recaptcha": "^2.1.0", - "react-i18next": "^11.18.1", + "prettier": "^3.3.3", + "react": "^18.3.1", + "react-beautiful-dnd": "^13.1.1", + "react-bootstrap": "^2.10.5", + "react-datepicker": "^7.5.0", + "react-dom": "^18.3.1", + "react-google-recaptcha": "^3.1.0", + "react-i18next": "^15.0.2", "react-icons": "^5.2.1", "react-infinite-scroll-component": "^6.1.0", - "react-redux": "^7.2.5", - "react-router-dom": "^6.23.1", - "react-scripts": "5.0.1", - "react-toastify": "^9.0.3", - "redux": "^4.1.1", - "redux-thunk": "^2.3.0", + "react-multi-carousel": "^2.8.5", + "react-redux": "^9.1.2", + "react-router-dom": "^6.27.0", + "react-toastify": "^10.0.6", + "react-tooltip": "^5.28.0", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", "sanitize-html": "^2.13.0", - "typedoc-plugin-markdown": "^4.0.3", - "typescript": "^4.3.5", - "web-vitals": "^1.0.1" + "typedoc": "^0.26.10", + "typedoc-plugin-markdown": "^4.2.1", + "typescript": "^5.6.3", + "vite": "^5.4.8", + "vite-plugin-environment": "^1.1.3", + "vite-tsconfig-paths": "^5.0.1", + "web-vitals": "^4.2.4" }, "scripts": { - "serve": "cross-env ESLINT_NO_DEV_ERRORS=true node ./scripts/config-overrides/custom_start.js", - "build": "node ./scripts/config-overrides/custom_build.js", - "test": "cross-env NODE_ENV=test node scripts/test.js --env=./scripts/custom-test-env.js --watchAll --coverage", + "serve": "cross-env ESLINT_NO_DEV_ERRORS=true vite --config config/vite.config.ts", + "build": "tsc && vite build --config config/vite.config.ts", + "preview": "vite preview --config config/vite.config.ts", + "test": "cross-env NODE_ENV=test jest --env=./scripts/custom-test-env.js --watchAll --coverage", "eject": "react-scripts eject", - "lint:check": "eslint \"**/*.{ts,tsx}\" --max-warnings=0", + "lint:check": "eslint \"**/*.{ts,tsx}\" --max-warnings=0 && python .github/workflows/eslint_disable_check.py", "lint:fix": "eslint --fix \"**/*.{ts,tsx}\"", "format:fix": "prettier --write \"**/*.{ts,tsx,json,scss,css}\"", "format:check": "prettier --check \"**/*.{ts,tsx,json,scss,css}\"", + "check-tsdoc": "node .github/workflows/check-tsdoc.js", "typecheck": "tsc --project tsconfig.json --noEmit", "prepare": "husky install", "jest-preview": "jest-preview", @@ -95,40 +104,47 @@ }, "devDependencies": { "@babel/plugin-proposal-private-property-in-object": "^7.21.11", - "@testing-library/jest-dom": "^5.14.1", - "@testing-library/react": "^11.1.0", + "@babel/preset-env": "^7.25.4", + "@babel/preset-react": "^7.25.7", + "@babel/preset-typescript": "^7.24.7", + "@testing-library/jest-dom": "^6.5.0", + "@testing-library/react": "^16.0.1", "@testing-library/user-event": "^12.1.10", "@types/inquirer": "^9.0.7", "@types/jest": "^26.0.24", "@types/js-cookie": "^3.0.6", - "@types/node": "^20.12.12", + "@types/node": "^22.5.4", "@types/node-fetch": "^2.6.10", - "@types/react": "^17.0.14", + "@types/react": "^18.3.3", + "@types/react-beautiful-dnd": "^13.1.8", "@types/react-bootstrap": "^0.32.32", - "@types/react-datepicker": "^4.1.4", - "@types/react-dom": "^17.0.9", - "@types/react-google-recaptcha": "^2.1.5", + "@types/react-datepicker": "^7.0.0", + "@types/react-dom": "^18.3.0", + "@types/react-google-recaptcha": "^2.1.9", "@types/react-router-dom": "^5.1.8", - "@types/sanitize-html": "^2.11.0", - "@typescript-eslint/eslint-plugin": "^5.9.0", - "@typescript-eslint/parser": "^5.9.0", + "@types/sanitize-html": "^2.13.0", + "@typescript-eslint/eslint-plugin": "^8.11.0", + "@typescript-eslint/parser": "^8.5.0", + "babel-jest": "^29.7.0", "cross-env": "^7.0.3", "eslint-config-prettier": "^9.1.0", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jest": "^25.3.4", - "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-react": "^7.34.1", - "eslint-plugin-tsdoc": "^0.2.17", - "husky": "^8.0.3", + "eslint-plugin-import": "^2.30.0", + "eslint-plugin-jest": "^28.8.0", + "eslint-plugin-prettier": "^5.2.1", + "eslint-plugin-react": "^7.37.1", + "eslint-plugin-tsdoc": "^0.3.0", + "husky": "^9.1.6", "identity-obj-proxy": "^3.0.0", "jest": "^27.4.5", "jest-localstorage-mock": "^2.4.19", "jest-location-mock": "^2.0.0", "jest-preview": "^0.3.1", - "lint-staged": "^15.2.7", + "lint-staged": "^15.2.8", "postcss-modules": "^6.0.0", - "sass": "^1.77.4", - "tsx": "^4.15.5" + "sass": "^1.77.8", + "tsx": "^4.19.1", + "vite-plugin-svgr": "^4.2.0", + "whatwg-fetch": "^3.6.20" }, "resolutions": { "@apollo/client": "^3.4.0-beta.19", diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 3539eb037e..67e0909bfd 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -76,5 +76,22 @@ "noFiltersApplied": "No filters applied", "manage": "Manage", "searchResultsFor": "Search results for {{text}}", - "none": "None" + "none": "None", + "Donate": "Donate", + "addedSuccessfully": "{{item}} added Successfully", + "updatedSuccessfully": "{{item}} updated Successfully", + "removedSuccessfully": "{{item}} removed Successfully", + "successfullyUpdated": "Successfully Updated", + "sessionWarning": "Your session will expire soon due to inactivity. Please interact with the page to extend your session.", + "sessionLogOut": "Your session has expired due to inactivity. Please log in again to continue.", + "sort": "Sort", + "all": "All", + "active": "Active", + "disabled": "Disabled", + "pending": "Pending", + "completed": "Completed", + "late": "Late", + "createdLatest": "Created Latest", + "createdEarliest": "Created Earliest", + "searchBy": "Search by {{item}}" } diff --git a/public/locales/en/errors.json b/public/locales/en/errors.json index 90b2acca9f..752c0db750 100644 --- a/public/locales/en/errors.json +++ b/public/locales/en/errors.json @@ -5,5 +5,7 @@ "notAuthorised": "Sorry! you are not Authorised!", "errorSendingMail": "Error sending mail", "emailNotRegistered": "Email not registered", - "notFoundMsg": "Oops! The Page you requested was not found!" + "notFoundMsg": "Oops! The Page you requested was not found!", + "errorOccurredCouldntCreate": "An error occurred. Couldn't create {{entity}}", + "errorLoading": "Error occured while loading {{entity}} data" } diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json index 6f62693892..1fabe32c6a 100644 --- a/public/locales/en/translation.json +++ b/public/locales/en/translation.json @@ -22,7 +22,25 @@ "numeric_value_check": "Atleaset one numeric value", "special_char_check": "Atleast one special character", "selectOrg": "Select an organization", - "afterRegister": "Successfully registered. Please wait for admin to approve your request." + "afterRegister": "Successfully registered. Please wait for admin to approve your request.", + "talawa_portal": "talawa_portal", + "login": "login", + "register": "register", + "firstName": "firstName", + "lastName": "lastName", + "email": "email", + "password": "password", + "confirmPassword": "confirmPassword", + "forgotPassword": "forgotPassword", + "enterEmail": "enterEmail", + "enterPassword": "enterPassword", + "talawaApiUnavailable": "talawaApiUnavailable", + "notAuthorised": "notAuthorised", + "notFound": "notFound", + "OR": "OR", + "admin": "admin", + "user": "user", + "loading": "loading" }, "userLoginPage": { "title": "Talawa Admin", @@ -38,7 +56,23 @@ "successfullyRegistered": "Successfully Registered. Please wait until you will be approved.", "userLogin": "User Login", "afterRegister": "Successfully registered. Please wait for admin to approve your request.", - "selectOrg": "Select an organization" + "selectOrg": "Select an organization", + "talawa_portal": "talawa_portal", + "login": "login", + "register": "register", + "firstName": "firstName", + "lastName": "lastName", + "email": "email", + "password": "password", + "confirmPassword": "confirmPassword", + "forgotPassword": "forgotPassword", + "enterEmail": "enterEmail", + "enterPassword": "enterPassword", + "talawaApiUnavailable": "talawaApiUnavailable", + "notAuthorised": "notAuthorised", + "notFound": "notFound", + "OR": "OR", + "loading": "loading" }, "latestEvents": { "eventCardTitle": "Upcoming Events", @@ -51,12 +85,19 @@ "noPostsCreated": "No Posts Created" }, "listNavbar": { - "roles": "Roles" + "roles": "Roles", + "talawa_portal": "talawa_portal", + "requests": "requests", + "logout": "logout" }, "leftDrawer": { "my organizations": "My Organizations", "requests": "Membership Requests", - "communityProfile": "Community Profile" + "communityProfile": "Community Profile", + "talawaAdminPortal": "talawaAdminPortal", + "menu": "menu", + "users": "users", + "logout": "logout" }, "leftDrawerOrg": { "Dashboard": "Dashboard", @@ -75,7 +116,13 @@ "notifications": "Notifications", "spamsThe": "spams the", "group": "group", - "noNotifications": "No Notifications" + "noNotifications": "No Notifications", + "talawaAdminPortal": "talawaAdminPortal", + "menu": "menu", + "talawa_portal": "talawa_portal", + "settings": "settings", + "logout": "logout", + "close": "close" }, "orgList": { "title": "Talawa Organizations", @@ -105,11 +152,25 @@ "manageFeaturesInfo": "Creation Successful ! Please select features that you want to enale for this organization from the plugin store.", "goToStore": "Go to Plugin Store", "enableEverything": "Enable Everything", - "sampleOrgSuccess": "Sample Organization Successfully Created" + "sampleOrgSuccess": "Sample Organization Successfully Created", + "name": "name", + "email": "email", + "searchByName": "searchByName", + "description": "description", + "location": "location", + "address": "address", + "displayImage": "displayImage", + "filter": "filter", + "cancel": "cancel", + "endOfResults": "endOfResults", + "noResultsFoundFor": "noResultsFoundFor", + "OR": "OR" }, "orgListCard": { "manage": "Manage", - "sampleOrganization": "Sample Organization" + "sampleOrganization": "Sample Organization", + "admins": "admins", + "members": "members" }, "paginationList": { "rowsPerPage": "rows per page", @@ -126,7 +187,11 @@ "acceptedSuccessfully": "Request accepted successfully", "rejectedSuccessfully": "Request rejected successfully", "noOrgErrorTitle": "Organizations Not Found", - "noOrgErrorDescription": "Please create an organization through dashboard" + "noOrgErrorDescription": "Please create an organization through dashboard", + "name": "name", + "email": "email", + "endOfResults": "endOfResults", + "noResultsFoundFor": "noResultsFoundFor" }, "users": { "title": "Talawa Roles", @@ -150,7 +215,25 @@ "visit": "Visit", "withdraw": "Widthdraw", "removeUserFrom": "Remove User from {{org}}", - "removeConfirmation": "Are you sure you want to remove '{{name}}' from organization '{{org}}'?" + "removeConfirmation": "Are you sure you want to remove '{{name}}' from organization '{{org}}'?", + "searchByName": "searchByName", + "users": "users", + "name": "name", + "email": "email", + "endOfResults": "endOfResults", + "admin": "admin", + "superAdmin": "superAdmin", + "user": "user", + "filter": "filter", + "noResultsFoundFor": "noResultsFoundFor", + "talawaApiUnavailable": "talawaApiUnavailable", + "cancel": "cancel", + "admins": "admins", + "members": "members", + "orgJoined": "orgJoined", + "MembershipRequestSent": "MembershipRequestSent", + "AlreadyJoined": "AlreadyJoined", + "errorOccured": "errorOccured" }, "communityProfile": { "title": "Community Profile", @@ -178,7 +261,12 @@ "latestPosts": "Latest Posts", "noPostsPresent": "No Posts Present", "membershipRequests": "Membership requests", - "noMembershipRequests": "No Membership requests present" + "noMembershipRequests": "No Membership requests present", + "location": "location", + "members": "members", + "admins": "admins", + "requests": "requests", + "talawaApiUnavailable": "talawaApiUnavailable" }, "organizationPeople": { "title": "Talawa Members", @@ -198,23 +286,106 @@ "enterLastName": "Enter your last name", "enterConfirmPassword": "Enter Password to confirm", "organization": "Organization", - "invalidDetailsMessage": "Please enter valid details." + "invalidDetailsMessage": "Please enter valid details.", + "members": "members", + "admins": "admins", + "users": "users", + "searchFirstName": "searchFirstName", + "searchLastName": "searchLastName", + "firstName": "firstName", + "lastName": "lastName", + "emailAddress": "emailAddress", + "enterEmail": "enterEmail", + "password": "password", + "enterPassword": "enterPassword", + "confirmPassword": "confirmPassword", + "create": "create", + "cancel": "cancel", + "user": "user", + "profile": "profile" + }, + "organizationTags": { + "title": "Organization Tags", + "createTag": "Create a new tag", + "manageTag": "Manage", + "editTag": "Edit", + "removeTag": "Remove", + "tagDetails": "Tag Details", + "tagName": "Name", + "tagType": "Type", + "tagNamePlaceholder": "Write the name of the tag", + "tagCreationSuccess": "New tag created successfully", + "tagUpdationSuccess": "Tag updated successfully", + "tagRemovalSuccess": "Tag deleted successfully", + "noTagsFound": "No tags found", + "removeUserTag": "Delete Tag", + "removeUserTagMessage": "Do you want to delete this tag?", + "addChildTag": "Add a Sub Tag" + }, + "manageTag": { + "title": "Tag Details", + "addPeopleToTag": "Add People to tag", + "viewProfile": "View", + "noAssignedMembersFound": "No one assigned", + "unassignUserTag": "Unassign Tag", + "unassignUserTagMessage": "Do you want to remove the tag from this user?", + "successfullyUnassigned": "Tag unassigned from user", + "addPeople": "Add People", + "add": "Add", + "subTags": "Sub Tags", + "assignedToAll": "Tag Assigned to All", + "successfullyAssignedToPeople": "Tag assigned successfully", + "errorOccurredWhileLoadingMembers": "Error occured while loading members", + "userName": "User Name", + "actions": "Actions", + "noOneSelected": "No One Selected", + "assignToTags": "Assign to Tags", + "removeFromTags": "Remove from Tags", + "assign": "Assign", + "remove": "Remove", + "successfullyAssignedToTags": "Successfully Assigned to Tags", + "successfullyRemovedFromTags": "Successfully Removed from Tags", + "errorOccurredWhileLoadingOrganizationUserTags": "Error occurred while loading organization tags", + "errorOccurredWhileLoadingSubTags": "Error occurred while loading subTags tags", + "removeUserTag": "Delete Tag", + "removeUserTagMessage": "Do you want to delete this tag? It delete all the sub tags and all the associations.", + "tagDetails": "Tag Details", + "tagName": "Name", + "tagUpdationSuccess": "Tag updated successfully", + "tagRemovalSuccess": "Tag deleted successfully", + "noTagSelected": "No Tag Selected", + "changeNameToEdit": "Change the name to make an update", + "selectTag": "Select Tag", + "collapse": "Collapse", + "expand": "Expand", + "tagNamePlaceholder": "Write the name of the tag", + "allTags": "All Tags" }, "userListCard": { "addAdmin": "Add Admin", - "addedAsAdmin": "User is added as admin." + "addedAsAdmin": "User is added as admin.", + "joined": "joined", + "talawaApiUnavailable": "talawaApiUnavailable" }, "orgAdminListCard": { "remove": "Remove", "removeAdmin": "Remove Admin", "removeAdminMsg": "Do you want to remove this admin?", - "adminRemoved": "The admin is removed." + "adminRemoved": "The admin is removed.", + "joined": "joined", + "no": "no", + "yes": "yes", + "talawaApiUnavailable": "talawaApiUnavailable" }, "orgPeopleListCard": { "remove": "Remove", "removeMember": "Remove Member", "removeMemberMsg": "Do you want to remove this member?", - "memberRemoved": "The Member is removed" + "memberRemoved": "The Member is removed", + "joined": "joined", + "no": "no", + "yes": "yes", + "talawaApiUnavailable": "talawaApiUnavailable" }, "organizationEvents": { "title": "Events", @@ -243,7 +414,17 @@ "never": "Never", "on": "On", "after": "After", - "occurences": "occurences" + "occurences": "occurences", + "startTime": "startTime", + "endTime": "endTime", + "eventLocation": "eventLocation", + "events": "events", + "description": "description", + "location": "location", + "startDate": "startDate", + "endDate": "endDate", + "talawaApiUnavailable": "talawaApiUnavailable", + "done": "done" }, "organizationActionItems": { "actionItemCategory": "Action Item Category", @@ -254,9 +435,8 @@ "assignmentDate": "Assignment Date", "active": "Active", "clearFilters": "Clear Filters", - "completed": "Completed", "completionDate": "Completion Date", - "createActionItem": "Create Action Items", + "createActionItem": "Create Action Item", "deleteActionItem": "Delete Action Item", "deleteActionItemMsg": "Do you want to remove this action item?", "details": "Details", @@ -265,20 +445,32 @@ "editActionItem": "Edit Action Item", "isCompleted": "Completed", "latest": "Latest", + "makeActive": "Active", "noActionItems": "No Action Items", "options": "Options", - "preCompletionNotes": "Pre Completion Notes", + "preCompletionNotes": "Notes", "actionItemActive": "Active", "markCompletion": "Mark Completion", "actionItemStatus": "Action Item Status", - "postCompletionNotes": "Post Completion Notes", + "postCompletionNotes": "Completion Notes", "selectActionItemCategory": "Select an action item category", "selectAssignee": "Select an assignee", "status": "Status", "successfulCreation": "Action Item created successfully", "successfulUpdation": "Action Item updated successfully", "successfulDeletion": "Action Item deleted successfully", - "title": "Action Items" + "title": "Action Items", + "category": "Category", + "allotedHours": "Alloted Hours", + "latestDueDate": "Latest Due Date", + "earliestDueDate": "Earliest Due Date", + "updateActionItem": "Update Action Item", + "noneUpdated": "None of the fields were updated", + "updateStatusMsg": "Are you sure you want to mark this action item as pending?", + "close": "close", + "eventActionItems": "eventActionItems", + "no": "no", + "yes": "yes" }, "organizationAgendaCategory": { "agendaCategoryDetails": "Agenda Category Details", @@ -297,6 +489,40 @@ "deleteAgendaCategory": "Delete Agenda Category", "deleteAgendaCategoryMsg": "Do you want to remove this agenda category?" }, + "agendaItems": { + "agendaItemDetails": "Agenda Item Details", + "updateAgendaItem": "Update Agenda Item", + "title": "Title", + "enterTitle": "Enter Title", + "sequence": "Sequence", + "description": "Description", + "enterDescription": "Enter Description", + "category": "Agenda Category", + "attachments": "Attachments", + "attachmentLimit": "Add any image file or video file upto 10MB", + "fileSizeExceedsLimit": "File size exceeds the limit which is 10MB", + "urls": "URLs", + "url": "add link to URL", + "enterUrl": "https://example.com", + "invalidUrl": "Please enter a valid URL", + "link": "Link", + "createdBy": "Created By", + "regular": "Regular", + "note": "Note", + "duration": "Duration", + "enterDuration": "mm:ss", + "options": "Options", + "createAgendaItem": "Create Agenda Item", + "noAgendaItems": "No Agenda Items", + "selectAgendaItemCategory": "Select an agenda item category", + "update": "Update", + "delete": "Delete", + "agendaItemCreated": "Agenda Item created successfully", + "agendaItemUpdated": "Agenda Item updated successfully", + "agendaItemDeleted": "Agenda Item deleted successfully", + "deleteAgendaItem": "Delete Agenda Item", + "deleteAgendaItemMsg": "Do you want to remove this agenda item?" + }, "eventListCard": { "deleteEvent": "Delete Event", "deleteEventMsg": "Do you want to remove this event?", @@ -321,39 +547,43 @@ "never": "Never", "on": "On", "after": "After", - "occurences": "occurences" + "occurences": "occurences", + "startTime": "startTime", + "endTime": "endTime", + "location": "location", + "no": "no", + "yes": "yes", + "description": "description", + "startDate": "startDate", + "endDate": "endDate", + "registerEvent": "registerEvent", + "close": "close", + "talawaApiUnavailable": "talawaApiUnavailable", + "done": "done" }, "funds": { "title": "Funds", "createFund": "Create Fund", "fundName": "Fund Name", - "fundId": "Fund ID", - "fundOptions": "Opitons", - "noFunds": "No Funds Found", - "fundDetails": "Fund Details", + "fundId": "Fund (Reference) ID", "taxDeductible": "Tax Deductible", - "enterfundName": "Enter Fund Name", - "enterfundId": "Enter Fund ID", - "default": "Default Fund", + "default": "Default", "archived": "Archived", - "nonArchive": "Non-Archived", "fundCreate": "Create Fund", "fundUpdate": "Update Fund", "fundDelete": "Delete Fund", - "manageFund": "Manage Fund", - "searchFullName": "Search By Name", "noFundsFound": "No Funds Found", "createdBy": "Created By", "createdOn": "Created On", "status": "Status", - "archiveFund": "Archive Fund", - "archiveFundMsg": "On Archiving this fund will remove it from the fund listing.Thisaction can be undone", "fundCreated": "Fund created successfully", "fundUpdated": "Fund updated successfully", "fundDeleted": "Fund deleted successfully", - "fundArchived": "Fund archived successfully", - "fundUnarchived": "Fund unarchived successfully", - "deleteFundMsg": "Do you want to remove this fund?" + "deleteFundMsg": "Are you sure you want to delete this fund?", + "createdLatest": "Created Latest", + "createdEarliest": "Created Earliest", + "viewCampaigns": "View Campaigns", + "searchByName": "searchByName" }, "fundCampaign": { "title": "Fundraising Campaigns", @@ -366,17 +596,21 @@ "deletedCampaign": "Campaign deleted successfully", "deleteCampaignMsg": "Are you sure you want to delete this campaign?", "noCampaigns": "No Campaigns Found", - "createCampaign": "Create Fund Campaign", - "updateCampaign": "Update Fund Campaign", - "manageCampaign": "Manage Fund Campaign", - "deleteCampaign": "Delete Fund Campaign", + "createCampaign": "Create Campaign", + "updateCampaign": "Update Campaign", + "deleteCampaign": "Delete Campaign", "currency": "Currency", "selectCurrency": "Select Currency", - "searchFullName": "Search By Name" + "searchFullName": "Search By Name", + "viewPledges": "View Pledges", + "noCampaignsFound": "No Campaigns Found", + "latestEndDate": "Latest End Date", + "earliestEndDate": "Earliest End Date", + "lowestGoal": "Lowest Goal", + "highestGoal": "Highest Goal" }, "pledges": { "title": "Fund Campaign Pledges", - "volunteers": "Volunteers", "pledgeAmount": "Pledge Amount", "pledgeOptions": "Options", "pledgeCreated": "Pledge created successfully", @@ -392,12 +626,18 @@ "editPledge": "Edit Pledge", "deletePledgeMsg": "Are you sure you want to delete this pledge?", "noPledges": "No Pledges Found", - "sort": "Sort", - "searchVolunteer": "Search By Volunteer", + "searchPledger": "Search By Pledgers", "highestAmount": "Highest Amount", "lowestAmount": "Lowest Amount", "latestEndDate": "Latest End Date", - "earliestEndDate": "Earliest End Date" + "earliestEndDate": "Earliest End Date", + "campaigns": "Campaigns", + "pledges": "Pledges", + "endsOn": "Ends on", + "raisedAmount": "Raised amount ", + "pledgedAmount": "Pledged amount", + "startDate": "startDate", + "endDate": "endDate" }, "orgPost": { "title": "Posts", @@ -425,7 +665,8 @@ "postCreatedSuccess": "Congratulations! You have Posted Something.", "pinPost": "Pin post", "Next": "Next Page", - "Previous": "Previous Page" + "Previous": "Previous Page", + "cancel": "cancel" }, "postNotFound": { "post": "Post", @@ -440,7 +681,8 @@ "user not found!": "User Not Found!", "member not found!": "Member Not Found!", "admin not found!": "Admin Not Found!", - "roles not found!": "Roles Not Found!" + "roles not found!": "Roles Not Found!", + "user": "user" }, "orgPostCard": { "author": "Author", @@ -459,7 +701,12 @@ "postDeleted": "Post deleted successfully.", "postUpdated": "Post Updated successfully.", "tag": " Your browser does not support the video tag", - "pin": "Pin Post" + "pin": "Pin Post", + "edit": "edit", + "no": "no", + "yes": "yes", + "close": "close", + "talawaApiUnavailable": "talawaApiUnavailable" }, "blockUnblockUser": { "title": "Block/Unblock User", @@ -475,13 +722,19 @@ "blockedUsers": "Blocked Users", "searchByFirstName": "Search By First Name", "searchByLastName": "Search By Last Name", - "noSpammerFound": "No spammer found" + "noSpammerFound": "No spammer found", + "searchByName": "searchByName", + "name": "name", + "email": "email", + "talawaApiUnavailable": "talawaApiUnavailable", + "noResultsFoundFor": "noResultsFoundFor" }, "eventManagement": { "title": "Event Management Dashboard", "dashboard": "Dashboard", "registrants": "Registrants", "eventActions": "Event Actions", + "eventAgendas": "Event Agendas", "eventStats": "Event Statistics", "attendance": "Attendance", "to": "TO" @@ -500,7 +753,10 @@ "errorSendingMail": "Error in sending mail.", "passwordMismatches": "Password and Confirm password mismatches.", "passwordChanges": "Password changes successfully.", - "OTPsent": "OTP is sent to your registered email." + "OTPsent": "OTP is sent to your registered email.", + "forgotPassword": "forgotPassword", + "password": "password", + "talawaApiUnavailable": "talawaApiUnavailable" }, "pageNotFound": { "title": "404 Not Found", @@ -538,7 +794,8 @@ "noData": "No data", "otherSettings": "Other Settings", "changeLanguage": "Change Language", - "manageCustomFields": "Manage Custom Fields" + "manageCustomFields": "Manage Custom Fields", + "agendaItemCategories": "Agenda Item Categories" }, "deleteOrg": { "deleteOrganization": "Delete Organization", @@ -546,16 +803,30 @@ "deleteMsg": "Do you want to delete this organization?", "confirmDelete": "Confirm Delete", "longDelOrgMsg": "By clicking on Delete Organization button the organization will be permanently deleted along with its events, tags and all related data.", - "successfullyDeletedSampleOrganization": "Successfully deleted sample Organization" + "successfullyDeletedSampleOrganization": "Successfully deleted sample Organization", + "cancel": "cancel" }, "userUpdate": { "appLanguageCode": "Default Language", - "userType": "User Type" + "userType": "User Type", + "firstName": "firstName", + "lastName": "lastName", + "email": "email", + "password": "password", + "admin": "admin", + "superAdmin": "superAdmin", + "displayImage": "displayImage", + "saveChanges": "saveChanges", + "cancel": "cancel" }, "userPasswordUpdate": { "previousPassword": "Previous Password", "newPassword": "New Password", - "confirmNewPassword": "Confirm New Password" + "confirmNewPassword": "Confirm New Password", + "passCantBeEmpty": "Password can't be empty", + "passNoMatch": "New and Confirm password do not match.", + "saveChanges": "saveChanges", + "cancel": "cancel" }, "orgDelete": { "deleteOrg": "Delete Org" @@ -563,7 +834,9 @@ "membershipRequest": { "accept": "Accept", "reject": "Reject", - "memberAdded": "it is accepted" + "memberAdded": "it is accepted", + "joined": "joined", + "talawaApiUnavailable": "talawaApiUnavailable" }, "orgUpdate": { "city": "City", @@ -577,7 +850,15 @@ "userRegistrationRequired": "User Registration Required", "isVisibleInSearch": "Visible in Search", "enterNameOrganization": "Enter Organization Name", - "successfulUpdated": "Organization updated successfully" + "successfulUpdated": "Organization updated successfully", + "name": "name", + "description": "description", + "location": "location", + "address": "address", + "displayImage": "displayImage", + "saveChanges": "saveChanges", + "cancel": "cancel", + "talawaApiUnavailable": "talawaApiUnavailable" }, "addOnRegister": { "addNew": "Add New", @@ -587,7 +868,9 @@ "pluginDesc": "Plugin Description", "pName": "Ex: Donations", "cName": "Ex: john Doe", - "pDesc": "This Plugin enables UI for" + "pDesc": "This Plugin enables UI for", + "close": "close", + "register": "register" }, "addOnStore": { "title": "Add On Store", @@ -644,14 +927,32 @@ "membershipRequests": "Membership requests", "adminForEvents": "Admin for events", "addedAsAdmin": "User is added as admin.", - "userType": "User Type" + "userType": "User Type", + "email": "email", + "displayImage": "displayImage", + "address": "address", + "delete": "delete", + "saveChanges": "saveChanges", + "joined": "joined", + "talawaApiUnavailable": "talawaApiUnavailable" + }, + "people": { + "title": "People", + "searchUsers": "Search users" }, "userLogin": { "login": "Login", "loginIntoYourAccount": "Login into your account", "invalidDetailsMessage": "Please enter a valid email and password.", "notAuthorised": "Sorry! you are not Authorised!", - "invalidCredentials": "Entered credentials are incorrect. Please enter valid credentials." + "invalidCredentials": "Entered credentials are incorrect. Please enter valid credentials.", + "forgotPassword": "forgotPassword", + "emailAddress": "emailAddress", + "enterEmail": "enterEmail", + "password": "password", + "enterPassword": "enterPassword", + "register": "register", + "talawaApiUnavailable": "talawaApiUnavailable" }, "userRegister": { "enterFirstName": "Enter your first name", @@ -661,7 +962,16 @@ "login": "Login", "afterRegister": "Successfully registered. Please wait for admin to approve your request.", "passwordNotMatch": "Password doesn't match. Confirm Password and try again.", - "invalidDetailsMessage": "Please enter valid details." + "invalidDetailsMessage": "Please enter valid details.", + "register": "register", + "firstName": "firstName", + "lastName": "lastName", + "emailAddress": "emailAddress", + "enterEmail": "enterEmail", + "password": "password", + "enterPassword": "enterPassword", + "confirmPassword": "confirmPassword", + "talawaApiUnavailable": "talawaApiUnavailable" }, "userNavbar": { "talawa": "Talawa", @@ -670,7 +980,10 @@ "events": "Events", "chat": "Chat", "donate": "Donate", - "language": "Language" + "language": "Language", + "settings": "settings", + "logout": "logout", + "close": "close" }, "userOrganizations": { "allOrganizations": "All Organizations", @@ -679,7 +992,11 @@ "selectOrganization": "Select an organization", "searchUsers": "Search users", "nothingToShow": "Nothing to show here.", - "organizations": "Organizations" + "organizations": "Organizations", + "search": "search", + "filter": "filter", + "searchByName": "searchByName", + "searchOrganizations": "Search Organization" }, "userSidebarOrg": { "yourOrganizations": "Your Organizations", @@ -687,22 +1004,32 @@ "viewAll": "View all", "talawaUserPortal": "Talawa User Portal", "my organizations": "My Organizations", - "communityProfile": "Community Profile" + "users": "Users", + "requests": "Requests", + "communityProfile": "Community Profile", + "logout": "Logout", + "settings": "Settings", + "chat": "Chat", + "menu": "menu" }, "organizationSidebar": { "viewAll": "View all", "events": "Events", "noEvents": "No Events to show", - "noMembers": "No Members to show" + "noMembers": "No Members to show", + "members": "members" }, "postCard": { "likes": "Likes", - "comments": "Comments" + "comments": "Comments", + "viewPost": "View Post", + "editPost": "Edit Post", + "postedOn": "Posted on {{date}}" }, "home": { "posts": "Posts", "post": "Post", - "title": "Title", + "title": "Posts", "textArea": "Something on your mind?", "feed": "Feed", "loading": "Loading", @@ -714,7 +1041,8 @@ "startPost": "Start a post", "media": "Media", "event": "Event", - "article": "Article" + "article": "Article", + "postNowVisibleInFeed": "Post now visible in feed" }, "settings": { "eventAttended": "Events Attended", @@ -750,7 +1078,7 @@ "widowed": "Widowed", "divorced": "Divorced", "engaged": "Engaged", - "seperated": "Seperated", + "separated": "Separated", "grade1": "Grade 1", "grade2": "Grade 2", "grade3": "Grade 3", @@ -770,9 +1098,18 @@ "fullTime": "Full Time", "partTime": "Part Time", "selectCountry": "Select a country", - "enterState": "Enter City or State" + "enterState": "Enter City or State", + "settings": "settings", + "firstName": "firstName", + "lastName": "lastName", + "emailAddress": "emailAddress", + "displayImage": "displayImage", + "address": "address", + "saveChanges": "saveChanges", + "joined": "joined" }, "donate": { + "title": "Donations", "donations": "Donations", "searchDonations": "Search donations", "donateForThe": "Donate for the", @@ -780,9 +1117,14 @@ "yourPreviousDonations": "Your Previous Donations", "donate": "Donate", "nothingToShow": "Nothing to show here.", - "success": "Donation Successful" + "success": "Donation Successful", + "invalidAmount": "Please enter a numerical value for the donation amount.", + "donationAmountDescription": "Please enter the numerical value for the donation amount.", + "donationOutOfRange": "Donation amount must be between {{min}} and {{max}}.", + "donateTo": "donateTo" }, "userEvents": { + "title": "Events", "nothingToShow": "Nothing to show here.", "createEvent": "Create Event", "recurring": "Recurring Event", @@ -797,13 +1139,25 @@ "publicEvent": "Is Public", "registerable": "Is Registerable", "monthlyCalendarView": "Monthly Calendar", - "yearlyCalendarView": "Yearly Calender" + "yearlyCalendarView": "Yearly Calender", + "startTime": "startTime", + "endTime": "endTime", + "enterLocation": "enterLocation", + "search": "search", + "cancel": "cancel", + "create": "create", + "eventDescription": "eventDescription", + "eventLocation": "eventLocation", + "startDate": "startDate", + "endDate": "endDate" }, "userEventCard": { "starts": "Starts", "ends": "Ends", "creator": "Creator", - "alreadyRegistered": "Already registered" + "alreadyRegistered": "Already registered", + "location": "location", + "register": "register" }, "advertisement": { "title": "Advertisements", @@ -825,10 +1179,23 @@ "deleteAdvertisement": "Delete Advertisement", "deleteAdvertisementMsg": "Do you want to remove this advertisement?", "view": "View", - "editAdvertisement": "Edit Advertisement" + "editAdvertisement": "Edit Advertisement", + "advertisementDeleted": "Advertisement deleted successfully.", + "endDateGreaterOrEqual": "End Date should be greater than or equal to Start Date", + "advertisementCreated": "Advertisement created successfully.", + "pHeading": "pHeading", + "delete": "delete", + "close": "close", + "no": "no", + "yes": "yes", + "edit": "edit", + "saveChanges": "saveChanges", + "endOfResults": "endOfResults" }, "userChat": { "chat": "Chat", + "search": "Search", + "messages": "Messages", "contacts": "Contacts" }, "userChatRoom": { @@ -847,20 +1214,28 @@ "String": "String", "Boolean": "Boolean", "Date": "Date", - "Number": "Number" + "Number": "Number", + "saveChanges": "saveChanges" }, "orgActionItemCategories": { "enableButton": "Enable", "disableButton": "Disable", "updateActionItemCategory": "Update", "actionItemCategoryName": "Name", - "actionItemCategoryDetails": "Action Item Category Details", + "categoryDetails": "Category Details", "enterName": "Enter Name", "successfulCreation": "Action Item Category created successfully", "successfulUpdation": "Action Item Category updated successfully", "sameNameConflict": "Please change the name to make an update", "categoryEnabled": "Action Item Category Enabled", - "categoryDisabled": "Action Item Category Disabled" + "categoryDisabled": "Action Item Category Disabled", + "noActionItemCategories": "No Action Item Categories", + "status": "Status", + "categoryDeleted": "Action Item Category deleted successfully", + "deleteCategory": "Delete Category", + "deleteCategoryMsg": "Are you sure you want to delete this Action Item Category?", + "createButton": "createButton", + "editButton": "editButton" }, "organizationVenues": { "title": "Venues", @@ -884,7 +1259,12 @@ "view": "View", "venueTitleError": "Venue title cannot be empty!", "venueCapacityError": "Capacity must be a positive number!", - "searchBy": "Search By" + "searchBy": "Search By", + "description": "description", + "edit": "edit", + "delete": "delete", + "name": "name", + "desc": "desc" }, "addMember": { "title": "Add Member", @@ -898,16 +1278,35 @@ "organization": "Organization", "invalidDetailsMessage": "Please provide all required details.", "passwordNotMatch": "Passwords do not match.", - "addMember": "Add Member" + "addMember": "Add Member", + "firstName": "firstName", + "lastName": "lastName", + "emailAddress": "emailAddress", + "enterEmail": "enterEmail", + "password": "password", + "enterPassword": "enterPassword", + "confirmPassword": "confirmPassword", + "cancel": "cancel", + "create": "create", + "user": "user", + "profile": "profile" }, "eventActionItems": { "title": "Action Items", - "createActionItem": "Create Action Items", + "createActionItem": "Create Action Item", "actionItemCategory": "Action Item Category", "selectActionItemCategory": "Select an action item category", "selectAssignee": "Select an assignee", - "preCompletionNotes": "Pre Completion Notes", - "postCompletionNotes": "Post Completion Notes", + "assignee": "Assignee", + "assigner": "Assigner", + "preCompletionNotes": "Notes", + "postCompletionNotes": "Completion Notes", + "assignmentDate": "Assignment Date", + "status": "Status", + "actionItemActive": "Active", + "actionItemStatus": "Action Item Status", + "actionItemCompleted": "Action Item Completed", + "markCompletion": "Mark Completion", "actionItemDetails": "Action Item Details", "dueDate": "Due Date", "completionDate": "Completion Date", @@ -918,6 +1317,37 @@ "successfulCreation": "Action Item created successfully", "successfulUpdation": "Action Item updated successfully", "notes": "Notes", - "save": "Save" + "save": "Save", + "yes": "yes", + "no": "no" + }, + "checkIn": { + "errorCheckingIn": "Error checking in", + "checkedInSuccessfully": "Checked in successfully" + }, + "eventRegistrantsModal": { + "errorAddingAttendee": "Error adding attendee", + "errorRemovingAttendee": "Error removing attendee" + }, + "userCampaigns": { + "title": "Fundraising Campaigns", + "searchByName": "Search by Name...", + "searchBy": "Search by", + "pledgers": "Pledgers", + "campaigns": "Campaigns", + "myPledges": "My Pledges", + "lowestAmount": "Lowest Amount", + "highestAmount": "Highest Amount", + "lowestGoal": "Lowest Goal", + "highestGoal": "Highest Goal", + "latestEndDate": "Latest End Date", + "earliestEndDate": "Earliest End Date", + "addPledge": "Add Pledge", + "viewPledges": "View Pledges", + "noPledges": "No Pledges Found", + "noCampaigns": "No Campaigns Found" + }, + "userPledges": { + "title": "My Pledges" } } diff --git a/public/locales/fr/common.json b/public/locales/fr/common.json index 46f4ac85cd..c1aadd7dbe 100644 --- a/public/locales/fr/common.json +++ b/public/locales/fr/common.json @@ -76,5 +76,22 @@ "noFiltersApplied": "Aucun filtre appliqué", "manage": "Gérer", "searchResultsFor": "Résultats de recherche pour {{text}}", - "none": "Aucun" + "none": "Aucun", + "sort": "Trier", + "Donate": "Faire un don", + "addedSuccessfully": "{{item}} ajouté avec succès", + "updatedSuccessfully": "{{item}} mis à jour avec succès", + "removedSuccessfully": "{{item}} supprimé avec succès", + "successfullyUpdated": "Mis à jour avec succès", + "sessionWarning": "Votre session expirera bientôt en raison de l'inactivité. Veuillez interagir avec la page pour prolonger votre session.", + "sessionLogOut": "Votre session a expiré en raison de l'inactivité. Veuillez vous reconnecter pour continuer.", + "all": "Tous", + "active": "Actif", + "disabled": "Désactivé", + "pending": "En attente", + "completed": "Complété", + "late": "En retard", + "createdLatest": "Créé le plus récemment", + "createdEarliest": "Créé le plus tôt", + "searchBy": "Rechercher par {{item}}" } diff --git a/public/locales/fr/errors.json b/public/locales/fr/errors.json index 5788340a97..e9a7cf4fd9 100644 --- a/public/locales/fr/errors.json +++ b/public/locales/fr/errors.json @@ -5,5 +5,7 @@ "notAuthorised": "Désolé! ", "errorSendingMail": "Erreur lors de l'envoi du courrier", "emailNotRegistered": "Email non enregistré", - "notFoundMsg": "Oops! " + "notFoundMsg": "Oops! ", + "errorOccurredCouldntCreate": "Une erreur s'est produite. Impossible de créer {{entity}}", + "errorLoading": "Une erreur s'est produite lors du chargement des données {{entity}}" } diff --git a/public/locales/fr/translation.json b/public/locales/fr/translation.json index 5dbd4e0b99..a79abcf91d 100644 --- a/public/locales/fr/translation.json +++ b/public/locales/fr/translation.json @@ -22,7 +22,25 @@ "numeric_value_check": "Au moins une valeur numérique", "special_char_check": "Au moins un caractère spécial", "selectOrg": "Sélectionnez une organisation", - "afterRegister": "Enregistré avec succès. " + "afterRegister": "Enregistré avec succès. ", + "talawa_portal": "Portail Talawa", + "login": "Connexion", + "register": "S'inscrire", + "firstName": "Prénom", + "lastName": "Nom de famille", + "email": "E-mail", + "password": "Mot de passe", + "confirmPassword": "Confirmer le mot de passe", + "forgotPassword": "Mot de passe oublié", + "enterEmail": "Entrer l'e-mail", + "enterPassword": "Entrer le mot de passe", + "talawaApiUnavailable": "API Talawa indisponible", + "notAuthorised": "Non autorisé", + "notFound": "Non trouvé", + "OR": "OU", + "admin": "Administrateur", + "user": "Utilisateur", + "loading": "Chargement" }, "userLoginPage": { "title": "Administrateur Talawa", @@ -38,7 +56,23 @@ "successfullyRegistered": "Enregistré avec succès. ", "userLogin": "Utilisateur en ligne", "afterRegister": "Enregistré avec succès. ", - "selectOrg": "Sélectionnez une organisation" + "selectOrg": "Sélectionnez une organisation", + "talawa_portal": "Portail Talawa", + "login": "Connexion", + "register": "S'inscrire", + "firstName": "Prénom", + "lastName": "Nom de famille", + "email": "E-mail", + "password": "Mot de passe", + "confirmPassword": "Confirmer le mot de passe", + "forgotPassword": "Mot de passe oublié", + "enterEmail": "Entrer l'e-mail", + "enterPassword": "Entrer le mot de passe", + "talawaApiUnavailable": "API Talawa indisponible", + "notAuthorised": "Non autorisé", + "notFound": "Non trouvé", + "OR": "OU", + "loading": "Chargement" }, "latestEvents": { "eventCardTitle": "évènements à venir", @@ -51,12 +85,19 @@ "noPostsCreated": "Aucun message créé" }, "listNavbar": { - "roles": "Les rôles" + "roles": "Les rôles", + "talawa_portal": "Portail Talawa", + "requests": "Demandes", + "logout": "Déconnexion" }, "leftDrawer": { "my organizations": "Mes organisations", "requests": "Demandes d'adhésion", - "communityProfile": "Profil de la communauté" + "communityProfile": "Profil de la communauté", + "talawaAdminPortal": "Portail Administrateur Talawa", + "menu": "Menu", + "users": "Utilisateurs", + "logout": "Déconnexion" }, "leftDrawerOrg": { "Dashboard": "Tableau de bord", @@ -75,7 +116,13 @@ "notifications": "Notifications", "spamsThe": "spamme le", "group": "groupe", - "noNotifications": "Aucune notification" + "noNotifications": "Aucune notification", + "talawaAdminPortal": "Portail Administrateur Talawa", + "menu": "Menu", + "talawa_portal": "Portail Talawa", + "settings": "Paramètres", + "logout": "Déconnexion", + "close": "Fermer" }, "orgList": { "title": "Organisations Talawa", @@ -105,11 +152,25 @@ "manageFeaturesInfo": "Création réussie ! ", "goToStore": "Accédez à la boutique de plugins", "enableEverything": "Activer tout", - "sampleOrgSuccess": "Exemple d'organisation créée avec succès" + "sampleOrgSuccess": "Exemple d'organisation créée avec succès", + "name": "Nom", + "email": "E-mail", + "searchByName": "Rechercher par nom", + "description": "Description", + "location": "Emplacement", + "address": "Adresse", + "displayImage": "Image d'affichage", + "filter": "Filtrer", + "cancel": "Annuler", + "endOfResults": "Fin des résultats", + "noResultsFoundFor": "Aucun résultat trouvé pour", + "OR": "OU" }, "orgListCard": { "manage": "Gérer", - "sampleOrganization": "Exemple d'organisation" + "sampleOrganization": "Exemple d'organisation", + "admins": "Administrateurs", + "members": "Membres" }, "paginationList": { "rowsPerPage": "lignes par page", @@ -126,7 +187,11 @@ "acceptedSuccessfully": "Demande acceptée avec succès", "rejectedSuccessfully": "Demande rejetée avec succès", "noOrgErrorTitle": "Organisations introuvables", - "noOrgErrorDescription": "Veuillez créer une organisation via le tableau de bord" + "noOrgErrorDescription": "Veuillez créer une organisation via le tableau de bord", + "name": "Nom", + "email": "E-mail", + "endOfResults": "Fin des résultats", + "noResultsFoundFor": "Aucun résultat trouvé pour" }, "users": { "title": "Rôles Talawa", @@ -150,7 +215,25 @@ "visit": "Visite", "withdraw": "Largeur de tirage", "removeUserFrom": "Supprimer l'Utilisateur de {{org}}", - "removeConfirmation": "Êtes-vous sûr de vouloir supprimer '{{name}}' de l'organisation '{{org}}' ?" + "removeConfirmation": "Êtes-vous sûr de vouloir supprimer '{{name}}' de l'organisation '{{org}}' ?", + "searchByName": "Rechercher par nom", + "users": "Utilisateurs", + "name": "Nom", + "email": "E-mail", + "endOfResults": "Fin des résultats", + "admin": "Administrateur", + "superAdmin": "Super Administrateur", + "user": "Utilisateur", + "filter": "Filtrer", + "noResultsFoundFor": "Aucun résultat trouvé pour", + "talawaApiUnavailable": "API Talawa indisponible", + "cancel": "Annuler", + "admins": "Administrateurs", + "members": "Membres", + "orgJoined": "Organisation Rejointe", + "MembershipRequestSent": "Demande d'adhésion envoyée", + "AlreadyJoined": "Déjà rejoint", + "errorOccured": "Une erreur s'est produite" }, "communityProfile": { "title": "Profil de la communauté", @@ -178,7 +261,12 @@ "latestPosts": "Derniers messages", "noPostsPresent": "Aucun message présent", "membershipRequests": "Demandes d'adhésion", - "noMembershipRequests": "Aucune demande d'adhésion présente" + "noMembershipRequests": "Aucune demande d'adhésion présente", + "location": "Emplacement", + "members": "Membres", + "admins": "Administrateurs", + "requests": "Demandes", + "talawaApiUnavailable": "API Talawa indisponible" }, "organizationPeople": { "title": "Membres Talawa", @@ -198,23 +286,106 @@ "enterLastName": "Entrez votre nom de famille", "enterConfirmPassword": "Entrez votre mot de passe pour confirmer", "organization": "Organisation", - "invalidDetailsMessage": "Veuillez saisir des informations valides." + "user": "Utilisateur", + "profile": "Profil", + "invalidDetailsMessage": "Veuillez saisir des informations valides.", + "members": "Membres", + "admins": "Administrateurs", + "users": "Utilisateurs", + "searchFirstName": "Rechercher par prénom", + "searchLastName": "Rechercher par nom de famille", + "firstName": "Prénom", + "lastName": "Nom de famille", + "emailAddress": "Adresse e-mail", + "enterEmail": "Entrer l'e-mail", + "password": "Mot de passe", + "enterPassword": "Entrer le mot de passe", + "confirmPassword": "Confirmer le mot de passe", + "create": "Créer", + "cancel": "Annuler" + }, + "organizationTags": { + "title": "Étiquettes d'Organisation", + "createTag": "Créer une nouvelle étiquette", + "manageTag": "Gérer", + "editTag": "Modifier", + "removeTag": "Supprimer", + "tagDetails": "Détails de l'Étiquette", + "tagName": "Nom", + "tagType": "Type", + "tagNamePlaceholder": "Écrire le nom de l'étiquette", + "tagCreationSuccess": "Nouvelle étiquette créée avec succès", + "tagUpdationSuccess": "Étiquette mise à jour avec succès", + "tagRemovalSuccess": "Étiquette supprimée avec succès", + "noTagsFound": "Aucune étiquette trouvée", + "removeUserTag": "Supprimer l'Étiquette", + "removeUserTagMessage": "Voulez-vous supprimer cette étiquette ?", + "addChildTag": "Ajouter une Sous-Étiquette" + }, + "manageTag": { + "title": "Détails de l'étiquette", + "addPeopleToTag": "Ajouter des personnes à l'étiquette", + "viewProfile": "Voir", + "noAssignedMembersFound": "Aucun membre assigné", + "unassignUserTag": "Désassigner l'étiquette", + "unassignUserTagMessage": "Voulez-vous retirer l'étiquette de cet utilisateur?", + "successfullyUnassigned": "Étiquette retirée de l'utilisateur", + "addPeople": "Ajouter des personnes", + "add": "Ajouter", + "subTags": "Sous-étiquettes", + "assignedToAll": "Étiquette attribuée à tous", + "successfullyAssignedToPeople": "Étiquette attribuée avec succès", + "errorOccurredWhileLoadingMembers": "Erreur survenue lors du chargement des membres", + "userName": "Nom d'utilisateur", + "actions": "Actions", + "noOneSelected": "Personne sélectionnée", + "assignToTags": "Attribuer aux étiquettes", + "removeFromTags": "Retirer des étiquettes", + "assign": "Attribuer", + "remove": "Retirer", + "successfullyAssignedToTags": "Attribué aux étiquettes avec succès", + "successfullyRemovedFromTags": "Retiré des étiquettes avec succès", + "errorOccurredWhileLoadingOrganizationUserTags": "Erreur lors du chargement des étiquettes de l'organisation", + "errorOccurredWhileLoadingSubTags": "Une erreur s'est produite lors du chargement des sous-étiquettes", + "removeUserTag": "Supprimer l'étiquette", + "removeUserTagMessage": "Voulez-vous supprimer cette étiquette ? Cela supprimera toutes les sous-étiquettes et toutes les associations.", + "tagDetails": "Détails de l'étiquette", + "tagName": "Nom de l'étiquette", + "tagUpdationSuccess": "Étiquette mise à jour avec succès", + "tagRemovalSuccess": "Étiquette supprimée avec succès", + "noTagSelected": "Aucune étiquette sélectionnée", + "changeNameToEdit": "Modifiez le nom pour faire une mise à jour", + "selectTag": "Sélectionner l'étiquette", + "collapse": "Réduire", + "expand": "Développer", + "tagNamePlaceholder": "Écrire le nom de l'étiquette", + "allTags": "Toutes les étiquettes" }, "userListCard": { "addAdmin": "Ajouter un administrateur", - "addedAsAdmin": "L'utilisateur est ajouté en tant qu'administrateur." + "addedAsAdmin": "L'utilisateur est ajouté en tant qu'administrateur.", + "joined": "Rejoint", + "talawaApiUnavailable": "API Talawa indisponible" }, "orgAdminListCard": { "remove": "Retirer", "removeAdmin": "Supprimer l'administrateur", "removeAdminMsg": "Voulez-vous supprimer cet administrateur ?", - "adminRemoved": "L'administrateur est supprimé." + "adminRemoved": "L'administrateur est supprimé.", + "joined": "Rejoint", + "no": "Non", + "yes": "Oui", + "talawaApiUnavailable": "API Talawa indisponible" }, "orgPeopleListCard": { "remove": "Retirer", "removeMember": "Supprimer un membre", "removeMemberMsg": "Voulez-vous supprimer ce membre ?", - "memberRemoved": "Le membre est supprimé" + "memberRemoved": "Le membre est supprimé", + "joined": "Rejoint", + "no": "Non", + "yes": "Oui", + "talawaApiUnavailable": "API Talawa indisponible" }, "organizationEvents": { "title": "Événements", @@ -245,7 +416,14 @@ "never": "Jamais", "on": "Sur", "after": "Après", - "occurences": "événements" + "occurences": "événements", + "events": "Événements", + "description": "Description", + "location": "Emplacement", + "startDate": "Date de début", + "endDate": "Date de fin", + "talawaApiUnavailable": "API Talawa indisponible", + "done": "Fait" }, "organizationActionItems": { "actionItemCategory": "Catégorie d'élément d'action", @@ -256,7 +434,6 @@ "assignmentDate": "Date d'affectation", "active": "Actif", "clearFilters": "Effacer les filtres", - "completed": "Complété", "completionDate": "Date d'achèvement", "createActionItem": "Créer un élément d'action", "deleteActionItem": "Supprimer l'élément d'action", @@ -267,6 +444,7 @@ "editActionItem": "Modifier l'élément d'action", "isCompleted": "Complété", "latest": "Dernier", + "makeActive": "Actif", "noActionItems": "Aucune action", "options": "Possibilités", "preCompletionNotes": "Notes préalables à l'achèvement", @@ -280,7 +458,18 @@ "successfulCreation": "Élément d'action créé avec succès", "successfulUpdation": "Élément d'action mis à jour avec succès", "successfulDeletion": "Élément d'action supprimé avec succès", - "title": "Éléments d'action" + "title": "Éléments d'action", + "category": "Catégorie", + "allotedHours": "Heures allouées", + "latestDueDate": "Date d'échéance la plus récente", + "earliestDueDate": "Date d'échéance la plus ancienne", + "updateActionItem": "Mettre à jour l'élément d'action", + "noneUpdated": "Aucun des champs n'a été mis à jour", + "updateStatusMsg": "Êtes-vous sûr de vouloir marquer cet élément d'action comme en attente?", + "close": "Fermer", + "eventActionItems": "Éléments d'action d'événement", + "no": "Non", + "yes": "Oui" }, "organizationAgendaCategory": { "agendaCategoryDetails": "Détails de la catégorie d'ordre du jour", @@ -299,6 +488,40 @@ "deleteAgendaCategory": "Supprimer la catégorie d'ordre du jour", "deleteAgendaCategoryMsg": "Souhaitez-vous supprimer cette catégorie d'ordre du jour ?" }, + "agendaItems": { + "agendaItemDetails": "Détails du point de l'ordre du jour", + "updateAgendaItem": "Mettre à jour le point de l'ordre du jour", + "title": "Titre", + "enterTitle": "Entrer le titre", + "sequence": "Ordre", + "description": "Description", + "enterDescription": "Entrer la description", + "category": "Catégorie de l'ordre du jour", + "attachments": "Pièces jointes", + "attachmentLimit": "Ajouter un fichier image ou vidéo jusqu'à 10 Mo", + "fileSizeExceedsLimit": "La taille du fichier dépasse la limite de 10 Mo", + "urls": "URL", + "url": "Ajouter un lien vers l'URL", + "enterUrl": "https://example.com", + "invalidUrl": "Veuillez saisir une URL valide", + "link": "Lien", + "createdBy": "Créé par", + "regular": "Régulier", + "note": "Note", + "duration": "Durée", + "enterDuration": "mm:ss", + "options": "Options", + "createAgendaItem": "Créer un point à l'ordre du jour", + "noAgendaItems": "Aucun point à l'ordre du jour", + "selectAgendaItemCategory": "Sélectionner une catégorie de point de l'ordre du jour", + "update": "Mettre à jour", + "delete": "Supprimer", + "agendaItemCreated": "Point de l'ordre du jour créé avec succès", + "agendaItemUpdated": "Point de l'ordre du jour mis à jour avec succès", + "agendaItemDeleted": "Point de l'ordre du jour supprimé avec succès", + "deleteAgendaItem": "Supprimer le point de l'ordre du jour", + "deleteAgendaItemMsg": "Voulez-vous supprimer ce point de l'ordre du jour ?" + }, "eventListCard": { "deleteEvent": "Supprimer l'événement", "deleteEventMsg": "Voulez-vous supprimer cet événement ?", @@ -325,62 +548,68 @@ "never": "Jamais", "on": "Sur", "after": "Après", - "occurences": "événements" + "occurences": "événements", + "location": "Lieu", + "no": "Non", + "yes": "Oui", + "description": "Description", + "startDate": "Date de début", + "endDate": "Date de fin", + "registerEvent": "Inscrire à l'événement", + "close": "Fermer", + "talawaApiUnavailable": "API Talawa non disponible", + "done": "Terminé" }, "funds": { "title": "Fonds", "createFund": "Créer un fonds", "fundName": "Nom du fonds", - "fundId": "ID du fonds", - "fundOptions": "Options", - "noFunds": "Aucun fonds trouvé", - "fundDetails": "Détails du fonds", - "taxDeductible": "Déductible d'impôts", - "enterfundName": "Entrez le nom du fonds", - "enterfundId": "Entrez l'ID du fonds", - "default": "Fonds de défaut", + "fundId": "ID de référence du fonds", + "taxDeductible": "Déductible d'impôt", + "default": "Par défaut", "archived": "Archivé", - "nonArchive": "Non archivé", "fundCreate": "Créer un fonds", "fundUpdate": "Mettre à jour le fonds", "fundDelete": "Supprimer le fonds", - "manageFund": "Gérer le fonds", - "searchFullName": "Rechercher par nom", + "searchByName": "Rechercher par nom", "noFundsFound": "Aucun fonds trouvé", "createdBy": "Créé par", - "createdOn": "Créé sur", + "createdOn": "Créé le", "status": "Statut", - "archiveFund": "Fonds d'archives", - "archiveFundMsg": "Lors de l'archivage, ce fonds le supprimera de la liste des fonds. Cette action peut être annulée.", "fundCreated": "Fonds créé avec succès", "fundUpdated": "Fonds mis à jour avec succès", "fundDeleted": "Fonds supprimé avec succès", - "fundArchived": "Fonds archivé avec succès", - "fundUnarchived": "Fonds désarchivé avec succès", - "deleteFundMsg": "Voulez-vous supprimer ce fonds ?" + "deleteFundMsg": "Êtes-vous sûr de vouloir supprimer ce fonds ?", + "createdLatest": "Créé le plus récemment", + "createdEarliest": "Créé le plus tôt", + "viewCampaigns": "Voir les campagnes" }, "fundCampaign": { "title": "Campagnes de collecte de fonds", "campaignName": "Nom de la campagne", - "campaignOptions": "Possibilités", + "campaignOptions": "Options", "fundingGoal": "Objectif de financement", "addCampaign": "Ajouter une campagne", "createdCampaign": "Campagne créée avec succès", "updatedCampaign": "Campagne mise à jour avec succès", "deletedCampaign": "Campagne supprimée avec succès", - "deleteCampaignMsg": "Êtes-vous sûr de vouloir supprimer cette campagne ?", + "deleteCampaignMsg": "Êtes-vous sûr de vouloir supprimer cette campagne ?", "noCampaigns": "Aucune campagne trouvée", - "createCampaign": "Créer une campagne de financement", - "updateCampaign": "Mettre à jour la campagne de financement", - "manageCampaign": "Gérer la campagne de financement", - "deleteCampaign": "Supprimer la campagne de financement", + "createCampaign": "Créer une campagne", + "updateCampaign": "Mettre à jour la campagne", + "deleteCampaign": "Supprimer la campagne", "currency": "Devise", - "selectCurrency": "Sélectionnez la devise", - "searchFullName": "Rechercher par nom" + "selectCurrency": "Sélectionner la devise", + "searchFullName": "Rechercher par nom", + "viewPledges": "Voir les promesses de dons", + "noCampaignsFound": "Aucune campagne trouvée", + "latestEndDate": "Dernière date de fin", + "earliestEndDate": "Date de fin la plus ancienne", + "lowestGoal": "Objectif le plus bas", + "highestGoal": "Objectif le plus élevé" }, "pledges": { "title": "Engagements de campagne de financement", - "volunteers": "Bénévoles", "pledgeAmount": "Montant de la promesse de don", "pledgeOptions": "Possibilités", "pledgeCreated": "Engagement créé avec succès", @@ -396,12 +625,18 @@ "editPledge": "Modifier l'engagement", "deletePledgeMsg": "Etes-vous sûr de vouloir supprimer cet engagement ?", "noPledges": "Aucun engagement trouvé", - "sort": "Trier", - "searchVolunteer": "Rechercher par bénévole", + "searchPledger": "Rechercher par les bailleurs de fonds", "highestAmount": "Montant le plus élevé", "lowestAmount": "Montant le plus bas", "latestEndDate": "Date de fin la plus récente", - "earliestEndDate": "Date de fin la plus proche" + "earliestEndDate": "Date de fin la plus proche", + "campaigns": "Campagnes", + "pledges": "Promesses de dons", + "endsOn": "Se termine le", + "raisedAmount": "Montant collecté", + "pledgedAmount": "Montant promis", + "startDate": "Date de début", + "endDate": "Date de fin" }, "orgPost": { "title": "Des postes", @@ -429,7 +664,8 @@ "postCreatedSuccess": "Toutes nos félicitations! ", "pinPost": "Épingler le message", "Next": "Page suivante", - "Previous": "Page précédente" + "Previous": "Page précédente", + "cancel": "Annuler" }, "postNotFound": { "post": "Poste", @@ -444,7 +680,8 @@ "user not found!": "Utilisateur non trouvé!", "member not found!": "Membre introuvable!", "admin not found!": "Administrateur introuvable !", - "roles not found!": "Rôles introuvables !" + "roles not found!": "Rôles introuvables !", + "user": "Utilisateur" }, "orgPostCard": { "author": "Auteur", @@ -463,7 +700,12 @@ "postDeleted": "Message supprimé avec succès.", "postUpdated": "Post mis à jour avec succès.", "tag": " Votre navigateur ne prend pas en charge la balise vidéo", - "pin": "Épingler le message" + "pin": "Épingler le message", + "edit": "Modifier", + "no": "Non", + "yes": "Oui", + "close": "Fermer", + "talawaApiUnavailable": "API Talawa non disponible" }, "blockUnblockUser": { "title": "Bloquer/débloquer un utilisateur", @@ -479,13 +721,19 @@ "blockedUsers": "Utilisateurs bloqués", "searchByFirstName": "Recherche par prénom", "searchByLastName": "Rechercher par nom de famille", - "noSpammerFound": "Aucun spammeur trouvé" + "noSpammerFound": "Aucun spammeur trouvé", + "searchByName": "Rechercher par nom", + "name": "Nom", + "email": "Email", + "talawaApiUnavailable": "API Talawa non disponible", + "noResultsFoundFor": "Aucun résultat trouvé pour" }, "eventManagement": { "title": "Gestion d'événements", "dashboard": "Tableau de bord", "registrants": "Inscrits", "eventActions": "Actions d'événement", + "eventAgendas": "Ordres du jour des événements", "eventStats": "Statistiques des événements", "to": "À" }, @@ -503,7 +751,10 @@ "errorSendingMail": "Erreur lors de l'envoi du courrier.", "passwordMismatches": "Mot de passe et Confirmer les incompatibilités de mot de passe.", "passwordChanges": "Le mot de passe a été modifié avec succès.", - "OTPsent": "OTP est envoyé à votre adresse e-mail enregistrée." + "OTPsent": "OTP est envoyé à votre adresse e-mail enregistrée.", + "forgotPassword": "Mot de passe oublié", + "password": "Mot de passe", + "talawaApiUnavailable": "API Talawa non disponible" }, "pageNotFound": { "404": "404", @@ -538,10 +789,11 @@ "actionItemCategories": "Catégories d'éléments d'action", "updateOrganization": "Mettre à jour l'organisation", "seeRequest": "Voir la demande", - "noData": "Pas de données", - "otherSettings": "Autres réglages", + "noData": "Aucune donnée", + "otherSettings": "Autres paramètres", "changeLanguage": "Changer de langue", - "manageCustomFields": "Gérer les champs personnalisés" + "manageCustomFields": "Gérer les champs personnalisés", + "agendaItemCategories": "Catégories d'éléments d'agenda" }, "deleteOrg": { "deleteOrganization": "Supprimer l'organisation", @@ -549,16 +801,30 @@ "deleteMsg": "Voulez-vous supprimer cette organisation ?", "confirmDelete": "Confirmation de la suppression", "longDelOrgMsg": "En cliquant sur le bouton Supprimer l'organisation, l'organisation sera définitivement supprimée ainsi que ses événements, balises et toutes les données associées.", - "successfullyDeletedSampleOrganization": "Exemple d'organisation supprimé avec succès" + "successfullyDeletedSampleOrganization": "Exemple d'organisation supprimé avec succès", + "cancel": "Annuler" }, "userUpdate": { "appLanguageCode": "Langage par défaut", - "userType": "Type d'utilisateur" + "userType": "Type d'utilisateur", + "firstName": "Prénom", + "lastName": "Nom de famille", + "email": "Email", + "password": "Mot de passe", + "admin": "Admin", + "superAdmin": "Super Admin", + "displayImage": "Image d'affichage", + "saveChanges": "Enregistrer les modifications", + "cancel": "Annuler" }, "userPasswordUpdate": { "previousPassword": "Mot de passe précédent", "newPassword": "nouveau mot de passe", - "confirmNewPassword": "Confirmer le nouveau mot de passe" + "confirmNewPassword": "Confirmer le nouveau mot de passe", + "passCantBeEmpty": "Le mot de passe ne peut pas être vide", + "passNoMatch": "Le nouveau mot de passe et la confirmation du mot de passe ne correspondent pas.", + "saveChanges": "Enregistrer les modifications", + "cancel": "Annuler" }, "orgDelete": { "deleteOrg": "Supprimer l'organisation" @@ -566,7 +832,9 @@ "membershipRequest": { "accept": "Accepter", "reject": "Rejeter", - "memberAdded": "c'est accepté" + "memberAdded": "c'est accepté", + "joined": "Rejoint", + "talawaApiUnavailable": "API Talawa non disponible" }, "orgUpdate": { "city": "Ville", @@ -580,7 +848,15 @@ "userRegistrationRequired": "Inscription de l'utilisateur requise", "isVisibleInSearch": "Visible dans la recherche", "enterNameOrganization": "Entrez le nom de l'organisation", - "successfulUpdated": "Organisation mise à jour avec succès" + "successfulUpdated": "Organisation mise à jour avec succès", + "name": "Nom", + "description": "Description", + "location": "Lieu", + "address": "Adresse", + "displayImage": "Image d'affichage", + "saveChanges": "Enregistrer les modifications", + "cancel": "Annuler", + "talawaApiUnavailable": "API Talawa non disponible" }, "addOnRegister": { "addNew": "Ajouter un nouveau", @@ -590,7 +866,9 @@ "pluginDesc": "Description du plugin", "pName": "Ex : Dons", "cName": "Ex : John Doe", - "pDesc": "Ce plugin active l'interface utilisateur pour" + "pDesc": "Ce plugin active l'interface utilisateur pour", + "close": "Fermer", + "register": "Inscription" }, "addOnStore": { "title": "Ajouter sur la boutique", @@ -601,7 +879,8 @@ "pHeading": "Plugins", "install": "installée", "available": "Disponible", - "pMessage": "Le plugin n'existe pas" + "pMessage": "Le plugin n'existe pas", + "filter": "filtrer" }, "addOnEntry": { "enable": "Activé", @@ -646,14 +925,32 @@ "membershipRequests": "Demandes d'adhésion", "adminForEvents": "Administrateur pour les événements", "addedAsAdmin": "L'utilisateur est ajouté en tant qu'administrateur.", - "userType": "Type d'utilisateur" + "userType": "Type d'utilisateur", + "email": "Email", + "displayImage": "Image d'affichage", + "address": "Adresse", + "delete": "Supprimer", + "saveChanges": "Enregistrer les modifications", + "joined": "Rejoint", + "talawaApiUnavailable": "API Talawa non disponible" + }, + "people": { + "title": "Personnes", + "searchUsers": "Rechercher des utilisateurs" }, "userLogin": { "login": "Se connecter", "loginIntoYourAccount": "Connectez-vous à votre compte", "invalidDetailsMessage": "Veuillez entrer un email et un mot de passe valides.", "notAuthorised": "Désolé! ", - "invalidCredentials": "Les informations d'identification saisies sont incorrectes. " + "invalidCredentials": "Les informations d'identification saisies sont incorrectes. ", + "forgotPassword": "Mot de passe oublié", + "emailAddress": "Adresse email", + "enterEmail": "Entrer l'email", + "password": "Mot de passe", + "enterPassword": "Entrer le mot de passe", + "register": "Inscription", + "talawaApiUnavailable": "API Talawa non disponible" }, "userRegister": { "enterFirstName": "Entrez votre prénom", @@ -663,7 +960,16 @@ "login": "Se connecter", "afterRegister": "Enregistré avec succès. ", "passwordNotMatch": "Le mot de passe ne correspond pas. ", - "invalidDetailsMessage": "Veuillez saisir des informations valides." + "invalidDetailsMessage": "Veuillez saisir des informations valides.", + "register": "Inscription", + "firstName": "Prénom", + "lastName": "Nom de famille", + "emailAddress": "Adresse email", + "enterEmail": "Entrer l'email", + "password": "Mot de passe", + "enterPassword": "Entrer le mot de passe", + "confirmPassword": "Confirmer le mot de passe", + "talawaApiUnavailable": "API Talawa non disponible" }, "userNavbar": { "talawa": "Talawa", @@ -672,7 +978,10 @@ "events": "Événements", "chat": "Chat", "donate": "Faire un don", - "language": "Langue" + "language": "Langue", + "settings": "Paramètres", + "logout": "Déconnexion", + "close": "Fermer" }, "userOrganizations": { "allOrganizations": "Toutes les organisations", @@ -681,7 +990,11 @@ "selectOrganization": "Sélectionnez une organisation", "searchUsers": "Rechercher des utilisateurs", "nothingToShow": "Rien à montrer ici.", - "organizations": "Organisations" + "organizations": "Organisations", + "search": "Rechercher", + "filter": "Filtrer", + "searchByName": "Rechercher par nom", + "searchOrganizations": "Rechercher Organisations" }, "userSidebarOrg": { "yourOrganizations": "Vos organisations", @@ -689,17 +1002,27 @@ "viewAll": "Voir tout", "talawaUserPortal": "Portail utilisateur Talawa", "my organizations": "Mes organisations", - "communityProfile": "Profil de la communauté" + "communityProfile": "Profil de la communauté", + "users": "utilisateurs", + "requests": "demandes", + "logout": "se déconnecter", + "settings": "paramètres", + "chat": "discussion", + "menu": "Menu" }, "organizationSidebar": { "viewAll": "Voir tout", "events": "Événements", "noEvents": "Aucun événement à afficher", - "noMembers": "Aucun membre à afficher" + "noMembers": "Aucun membre à afficher", + "members": "Membres" }, "postCard": { "likes": "Aime", - "comments": "commentaires" + "comments": "commentaires", + "viewPost": "Voir le message", + "editPost": "Modifier le message", + "postedOn": "Publié le {{date}}" }, "home": { "posts": "Des postes", @@ -716,7 +1039,8 @@ "startPost": "Démarrer un message", "media": "Médias", "event": "Événement", - "article": "Article" + "article": "Article", + "postNowVisibleInFeed": "Le post est maintenant visible dans le fil d'actualité" }, "settings": { "eventAttended": "Événements Assistés", @@ -752,7 +1076,7 @@ "widowed": "Veuf", "divorced": "Divorcé", "engaged": "Engagé", - "seperated": "Séparé", + "separated": "Séparé", "grade1": "1re année", "grade2": "2e année", "grade3": "3e année", @@ -772,9 +1096,18 @@ "fullTime": "À temps plein", "partTime": "À temps partiel", "selectCountry": "Choisissez un pays", - "enterState": "Entrez la ville ou l'état" + "enterState": "Entrez la ville ou l'état", + "settings": "Paramètres", + "firstName": "Prénom", + "lastName": "Nom de famille", + "emailAddress": "Adresse email", + "displayImage": "Image d'affichage", + "address": "Adresse", + "saveChanges": "Enregistrer les modifications", + "joined": "Rejoint" }, "donate": { + "title": "Des dons", "donations": "Des dons", "searchDonations": "Rechercher des dons", "donateForThe": "Faites un don pour le", @@ -782,9 +1115,14 @@ "yourPreviousDonations": "Vos dons précédents", "donate": "Faire un don", "nothingToShow": "Rien à montrer ici.", - "success": "Don réussi" + "success": "Don réussi", + "invalidAmount": "Veuillez saisir une valeur numérique pour le montant du don.", + "donationAmountDescription": "Veuillez saisir la valeur numérique du montant du don.", + "donationOutOfRange": "Le montant du don doit être compris entre {{min}} et {{max}}.", + "donateTo": "Faire un don à" }, "userEvents": { + "title": "Événements", "nothingToShow": "Rien à montrer ici.", "createEvent": "Créer un évènement", "recurring": "Événement récurrent", @@ -802,13 +1140,22 @@ "publicEvent": "est public", "registerable": "Est enregistrable", "monthlyCalendarView": "Calendrier mensuel", - "yearlyCalendarView": "Calendrier annuel" + "yearlyCalendarView": "Calendrier annuel", + "search": "Rechercher", + "cancel": "Annuler", + "create": "Créer", + "eventDescription": "Description de l'événement", + "eventLocation": "Lieu de l'événement", + "startDate": "Date de début", + "endDate": "Date de fin" }, "userEventCard": { "starts": "Départs", "ends": "Prend fin", "creator": "Créateur", - "alreadyRegistered": "Déjà enregistré" + "alreadyRegistered": "Déjà enregistré", + "location": "Lieu", + "register": "Inscription" }, "advertisement": { "title": "Annonces", @@ -830,11 +1177,24 @@ "deleteAdvertisement": "Supprimer la publicité", "deleteAdvertisementMsg": "Voulez-vous supprimer cette publicité ?", "view": "Voir", - "editAdvertisement": "Modifier l'annonce" + "editAdvertisement": "Modifier l'annonce", + "advertisementDeleted": "Publicité supprimée avec succès.", + "endDateGreaterOrEqual": "La date de fin doit être supérieure ou égale à la date de début", + "advertisementCreated": "Publicité créée avec succès.", + "pHeading": "Titre principal", + "delete": "Supprimer", + "close": "Fermer", + "no": "Non", + "yes": "Oui", + "edit": "Modifier", + "saveChanges": "Enregistrer les modifications", + "endOfResults": "Fin des résultats" }, "userChat": { "chat": "Chat", - "contacts": "Contacts" + "contacts": "Contacts", + "search": "rechercher", + "messages": "messages" }, "userChatRoom": { "selectContact": "Sélectionnez un contact pour démarrer la conversation", @@ -852,20 +1212,28 @@ "String": "Chaîne", "Boolean": "Booléen", "Date": "Date", - "Number": "Nombre" + "Number": "Nombre", + "saveChanges": "Enregistrer les modifications" }, "orgActionItemCategories": { "enableButton": "Activer", "disableButton": "Désactiver", "updateActionItemCategory": "Mise à jour", "actionItemCategoryName": "Nom", - "actionItemCategoryDetails": "Détails de la catégorie d'élément d'action", + "categoryDetails": "Détails de la catégorie", "enterName": "Entrez le nom", "successfulCreation": "Catégorie d'élément d'action créée avec succès", "successfulUpdation": "Catégorie d'élément d'action mise à jour avec succès", "sameNameConflict": "Veuillez changer le nom pour effectuer une mise à jour", "categoryEnabled": "Catégorie d'élément d'action activée", - "categoryDisabled": "Catégorie d'élément d'action désactivée" + "categoryDisabled": "Catégorie d'élément d'action désactivée", + "noActionItemCategories": "Aucune catégorie d'élément d'action", + "status": "Statut", + "categoryDeleted": "Catégorie d'élément d'action supprimée avec succès", + "deleteCategory": "Supprimer la catégorie", + "deleteCategoryMsg": "Êtes-vous sûr de vouloir supprimer cette catégorie d'élément d'action ?", + "createButton": "Créer", + "editButton": "Modifier" }, "organizationVenues": { "title": "Lieux", @@ -889,7 +1257,12 @@ "view": "Voir", "venueTitleError": "Le titre du lieu ne peut pas être vide !", "venueCapacityError": "La capacité doit être un nombre positif !", - "searchBy": "Recherché par" + "searchBy": "Recherché par", + "description": "Description", + "edit": "Modifier", + "delete": "Supprimer", + "name": "Nom", + "desc": "Description" }, "addMember": { "title": "Ajouter un membre", @@ -903,7 +1276,18 @@ "organization": "Organisation", "invalidDetailsMessage": "Veuillez fournir tous les détails requis.", "passwordNotMatch": "Les mots de passe ne correspondent pas.", - "addMember": "Ajouter un membre" + "addMember": "Ajouter un membre", + "firstName": "Prénom", + "lastName": "Nom de famille", + "emailAddress": "Adresse email", + "enterEmail": "Entrer l'email", + "password": "Mot de passe", + "enterPassword": "Entrer le mot de passe", + "confirmPassword": "Confirmer le mot de passe", + "cancel": "Annuler", + "create": "Créer", + "user": "Utilisateur", + "profile": "Profil" }, "eventActionItems": { "title": "Éléments d'action", @@ -911,8 +1295,8 @@ "actionItemCategory": "Catégorie d'élément d'action", "selectActionItemCategory": "Sélectionnez une catégorie d'élément d'action", "selectAssignee": "Sélectionnez un responsable", - "preCompletionNotes": "Notes préalables à l'achèvement", - "postCompletionNotes": "Notes post-achèvement", + "preCompletionNotes": "Remarques", + "postCompletionNotes": "Notes d'achèvement", "actionItemDetails": "Détails de l'action", "dueDate": "Date d'échéance", "completionDate": "Date d'achèvement", @@ -923,6 +1307,45 @@ "successfulCreation": "Élément d'action créé avec succès", "successfulUpdation": "Élément d'action mis à jour avec succès", "notes": "Remarques", - "save": "Sauvegarder" + "assignee": "Cessionnaire", + "assigner": "Assigner", + "assignmentDate": "Date d'affectation", + "status": "Statut", + "actionItemActive": "Actif", + "actionItemStatus": "Statut de l'action", + "actionItemCompleted": "Élément d'action terminé", + "markCompletion": "Marquer l'achèvement", + "save": "Sauvegarder", + "yes": "Oui", + "no": "Non" + }, + "checkIn": { + "errorCheckingIn": "Erreur lors de l'enregistrement", + "checkedInSuccessfully": "Enregistrement réussi" + }, + "eventRegistrantsModal": { + "errorAddingAttendee": "Erreur lors de l'ajout du participant", + "errorRemovingAttendee": "Erreur lors de la suppression du participant" + }, + "userCampaigns": { + "title": "Campagnes de financement", + "searchByName": "Rechercher par nom...", + "searchBy": "Rechercher par", + "pledgers": "Contributeurs", + "campaigns": "Campagnes", + "myPledges": "Mes Promesses", + "lowestAmount": "Montant le plus bas", + "highestAmount": "Montant le plus élevé", + "lowestGoal": "Objectif le plus bas", + "highestGoal": "Objectif le plus élevé", + "latestEndDate": "Date de fin la plus tardive", + "earliestEndDate": "Date de fin la plus proche", + "addPledge": "Ajouter une promesse", + "viewPledges": "Voir les promesses", + "noPledges": "Aucune promesse trouvée", + "noCampaigns": "Aucune campagne trouvée" + }, + "userPledges": { + "title": "Mes Promesses" } } diff --git a/public/locales/hi/common.json b/public/locales/hi/common.json index cb30270abb..7484872071 100644 --- a/public/locales/hi/common.json +++ b/public/locales/hi/common.json @@ -76,5 +76,22 @@ "noFiltersApplied": "कोई फ़िल्टर लागू नहीं हैं", "manage": "प्रबंधित करें", "searchResultsFor": "{{text}} के लिए खोज परिणाम", - "none": "कोई नहीं" + "none": "कोई नहीं", + "sort": "क्रम से लगाना", + "Donate": "दान करें", + "addedSuccessfully": "{{item}} सफलतापूर्वक जोड़ा गया", + "updatedSuccessfully": "{{item}} सफलतापूर्वक अपडेट किया गया", + "removedSuccessfully": "{{item}} सफलतापूर्वक हटाया गया", + "sessionWarning": "आपका सत्र निष्क्रियता के कारण जल्द ही समाप्त हो जाएगा। कृपया अपने सत्र को बढ़ाने के लिए पृष्ठ के साथ बातचीत करें।", + "sessionLogOut": "निष्क्रियता के कारण आपका सत्र समाप्त हो गया है। कृपया जारी रखने के लिए पुनः लॉगिन करें।", + "successfullyUpdated": "सफलतापूर्वक अपडेट किया गया", + "all": "सभी", + "active": "सक्रिय", + "disabled": "अक्षम", + "pending": "लंबित", + "completed": "पूरा हुआ", + "late": "देर से", + "createdLatest": "नवीनतम बनाया गया", + "createdEarliest": "सबसे पहले बनाया गया", + "searchBy": "के द्वारा खोजें {{item}}" } diff --git a/public/locales/hi/errors.json b/public/locales/hi/errors.json index 5e08ee8e9e..63b6c3f5d3 100644 --- a/public/locales/hi/errors.json +++ b/public/locales/hi/errors.json @@ -5,5 +5,7 @@ "notAuthorised": "क्षमा मांगना! ", "errorSendingMail": "मेल भेजने में त्रुटि", "emailNotRegistered": "ईमेल पंजीकृत नहीं है", - "notFoundMsg": "उफ़! " + "notFoundMsg": "उफ़! ", + "errorOccurredCouldntCreate": "एक त्रुटि हुई। {{entity}} नहीं बना सके", + "errorLoading": "{{entity}} डेटा लोड करते समय त्रुटि हुई" } diff --git a/public/locales/hi/translation.json b/public/locales/hi/translation.json index b53e1ee428..72168dc875 100644 --- a/public/locales/hi/translation.json +++ b/public/locales/hi/translation.json @@ -1,49 +1,83 @@ { "loginPage": { - "title": "तलावा प्रशासन", - "fromPalisadoes": "पैलिसाडोज़ फाउंडेशन के स्वयंसेवकों द्वारा एक खुला स्रोत एप्लिकेशन", + "title": "तालावा व्यवस्थापक", + "fromPalisadoes": "Palisadoes फाउंडेशन स्वयंसेवकों द्वारा विकसित एक ओपन-सोर्स एप्लिकेशन", "userLogin": "उपयोगकर्ता लॉगिन", - "atleast_8_char_long": "कम से कम 8 अक्षर लंबा", - "atleast_6_char_long": "कम से कम 6 अक्षर लंबा", - "firstName_invalid": "प्रथम नाम में केवल छोटे और बड़े अक्षर होने चाहिए", - "lastName_invalid": "अंतिम नाम में केवल छोटे और बड़े अक्षर होने चाहिए", - "password_invalid": "पासवर्ड में कम से कम एक लोअरकेस अक्षर, एक अपरकेस अक्षर, एक संख्यात्मक मान और एक विशेष अक्षर होना चाहिए", + "atleast_8_char_long": "कम से कम 8 अक्षर लंबे", + "atleast_6_char_long": "कम से कम 6 अक्षर लंबे", + "firstName_invalid": "पहला नाम केवल छोटे और बड़े अक्षरों को शामिल कर सकता है", + "lastName_invalid": "अंतिम नाम केवल छोटे और बड़े अक्षरों को शामिल कर सकता है", + "password_invalid": "पासवर्ड में कम से कम 1 छोटा अक्षर, 1 बड़ा अक्षर, 1 संख्या और 1 विशेष अक्षर होना चाहिए", "email_invalid": "ईमेल में कम से कम 8 अक्षर होने चाहिए", - "Password_and_Confirm_password_mismatches.": "पासवर्ड और पासवर्ड बेमेल होने की पुष्टि करें।", - "doNotOwnAnAccount": "क्या आपके पास कोई खाता नहीं है?", + "Password_and_Confirm_password_mismatches.": "पासवर्ड और पुष्टि पासवर्ड मेल नहीं खाते।", + "doNotOwnAnAccount": "कोई खाता नहीं है?", "captchaError": "कैप्चा त्रुटि!", - "Please_check_the_captcha": "कृपया, कैप्चा जांचें।", - "Something_went_wrong": "कुछ ग़लत हो गया, कृपया कुछ देर बाद प्रयास करें।", - "passwordMismatches": "पासवर्ड और पासवर्ड बेमेल होने की पुष्टि करें।", - "fillCorrectly": "सभी विवरण सही-सही भरें।", - "successfullyRegistered": "पंजीकरण सफलतापूर्वक हो गया है। ", + "Please_check_the_captcha": "कृपया कैप्चा जांचें।", + "Something_went_wrong": "कुछ गलत हो गया, कृपया बाद में पुनः प्रयास करें।", + "passwordMismatches": "पासवर्ड और पुष्टि पासवर्ड मेल नहीं खाते।", + "fillCorrectly": "सभी विवरण सही ढंग से भरें।", + "successfullyRegistered": "सफलतापूर्वक पंजीकृत।", "lowercase_check": "कम से कम एक छोटा अक्षर", "uppercase_check": "कम से कम एक बड़ा अक्षर", - "numeric_value_check": "कम से कम एक संख्यात्मक मान निर्धारित करें", - "special_char_check": "कम से कम एक विशेष पात्र", + "numeric_value_check": "कम से कम एक संख्या", + "special_char_check": "कम से कम एक विशेष अक्षर", "selectOrg": "एक संगठन चुनें", - "afterRegister": "पंजीकरण सफलतापूर्वक हो गया है। " + "afterRegister": "सफलतापूर्वक पंजीकृत।", + "talawa_portal": "तालावा पोर्टल", + "login": "लॉगिन", + "register": "पंजीकरण", + "firstName": "पहला नाम", + "lastName": "अंतिम नाम", + "email": "ईमेल", + "password": "पासवर्ड", + "confirmPassword": "पुष्टि पासवर्ड", + "forgotPassword": "पासवर्ड भूल गए", + "enterEmail": "ईमेल दर्ज करें", + "enterPassword": "पासवर्ड दर्ज करें", + "talawaApiUnavailable": "तालावा एपीआई अनुपलब्ध", + "notAuthorised": "अनधिकृत", + "notFound": "नहीं मिला", + "OR": "या", + "admin": "व्यवस्थापक", + "user": "उपयोगकर्ता", + "loading": "लोड हो रहा है" }, "userLoginPage": { - "title": "तलावा प्रशासन", - "fromPalisadoes": "पैलिसाडोज़ फाउंडेशन के स्वयंसेवकों द्वारा एक खुला स्रोत एप्लिकेशन", - "atleast_8_char_long": "कम से कम 8 अक्षर लंबा", - "Password_and_Confirm_password_mismatches.": "पासवर्ड और पासवर्ड बेमेल होने की पुष्टि करें।", - "doNotOwnAnAccount": "क्या आपके पास कोई खाता नहीं है?", + "title": "तालावा व्यवस्थापक", + "fromPalisadoes": "Palisadoes फाउंडेशन स्वयंसेवकों द्वारा विकसित एक ओपन-सोर्स एप्लिकेशन", + "atleast_8_char_long": "कम से कम 8 अक्षर लंबे", + "Password_and_Confirm_password_mismatches.": "पासवर्ड और पुष्टि पासवर्ड मेल नहीं खाते।", + "doNotOwnAnAccount": "कोई खाता नहीं है?", "captchaError": "कैप्चा त्रुटि!", - "Please_check_the_captcha": "कृपया, कैप्चा जांचें।", - "Something_went_wrong": "कुछ ग़लत हो गया, कृपया कुछ देर बाद प्रयास करें।", - "passwordMismatches": "पासवर्ड और पासवर्ड बेमेल होने की पुष्टि करें।", - "fillCorrectly": "सभी विवरण सही-सही भरें।", - "successfullyRegistered": "पंजीकरण सफलतापूर्वक हो गया है। ", + "Please_check_the_captcha": "कृपया कैप्चा जांचें।", + "Something_went_wrong": "कुछ गलत हो गया, कृपया बाद में पुनः प्रयास करें।", + "passwordMismatches": "पासवर्ड और पुष्टि पासवर्ड मेल नहीं खाते।", + "fillCorrectly": "सभी विवरण सही ढंग से भरें।", + "successfullyRegistered": "सफलतापूर्वक पंजीकृत।", "userLogin": "उपयोगकर्ता लॉगिन", - "afterRegister": "पंजीकरण सफलतापूर्वक हो गया है। ", - "selectOrg": "एक संगठन चुनें" + "afterRegister": "सफलतापूर्वक पंजीकृत।", + "selectOrg": "एक संगठन चुनें", + "talawa_portal": "तालावा पोर्टल", + "login": "लॉगिन", + "register": "पंजीकरण", + "firstName": "पहला नाम", + "lastName": "अंतिम नाम", + "email": "ईमेल", + "password": "पासवर्ड", + "confirmPassword": "पुष्टि पासवर्ड", + "forgotPassword": "पासवर्ड भूल गए", + "enterEmail": "ईमेल दर्ज करें", + "enterPassword": "पासवर्ड दर्ज करें", + "talawaApiUnavailable": "तालावा एपीआई अनुपलब्ध", + "notAuthorised": "अनधिकृत", + "notFound": "नहीं मिला", + "OR": "या", + "loading": "लोड हो रहा है" }, "latestEvents": { - "eventCardTitle": "आगामी कार्यक्रम", + "eventCardTitle": "आगामी घटनाएँ", "eventCardSeeAll": "सभी देखें", - "noEvents": "कोई आगामी ईवेंट नहीं" + "noEvents": "कोई आगामी घटनाएँ नहीं हैं" }, "latestPosts": { "latestPostsTitle": "नवीनतम पोस्ट", @@ -51,65 +85,92 @@ "noPostsCreated": "कोई पोस्ट नहीं बनाई गई" }, "listNavbar": { - "roles": "भूमिकाएँ" + "roles": "भूमिकाएँ", + "talawa_portal": "तालावा पोर्टल", + "requests": "अनुरोध", + "logout": "लॉगआउट" }, "leftDrawer": { "my organizations": "मेरे संगठन", "requests": "सदस्यता अनुरोध", - "communityProfile": "सामुदायिक प्रोफ़ाइल" + "communityProfile": "समुदाय प्रोफ़ाइल", + "talawaAdminPortal": "तालावा व्यवस्थापक पोर्टल", + "menu": "मेनू", + "users": "उपयोगकर्ता", + "logout": "लॉगआउट" }, "leftDrawerOrg": { "Dashboard": "डैशबोर्ड", "People": "लोग", - "Events": "आयोजन", + "Events": "घटनाएँ", "Contributions": "योगदान", - "Posts": "पदों", - "Block/Unblock": "ब्लॉक/अनब्लॉक करें", - "Plugins": "प्लग-इन", + "Posts": "पोस्ट", + "Block/Unblock": "ब्लॉक/अनब्लॉक", + "Plugins": "प्लगइन्स", "Plugin Store": "प्लगइन स्टोर", - "Advertisement": "विज्ञापनों", + "Advertisement": "विज्ञापन", "allOrganizations": "सभी संगठन", - "yourOrganization": "आपकी संगठन", - "notification": "अधिसूचना", + "yourOrganization": "आपका संगठन", + "notification": "सूचना", "language": "भाषा", - "notifications": "सूचनाएं", - "spamsThe": "स्पैम करता है", + "notifications": "सूचनाएँ", + "spamsThe": "स्पैम", "group": "समूह", - "noNotifications": "कोई सूचनाएं नहीं" + "noNotifications": "कोई सूचनाएँ नहीं", + "talawaAdminPortal": "तालावा व्यवस्थापक पोर्टल", + "menu": "मेनू", + "talawa_portal": "तालावा पोर्टल", + "settings": "सेटिंग्स", + "logout": "लॉगआउट", + "close": "बंद करें" }, "orgList": { - "title": "तलावा संगठन", + "title": "तालावा संगठन", "you": "आप", - "designation": "पद का नाम", + "designation": "पदनाम", "my organizations": "मेरे संगठन", "createOrganization": "संगठन बनाएं", "createSampleOrganization": "नमूना संगठन बनाएं", "city": "शहर", - "countryCode": "कंट्री कोड", - "dependentLocality": "आश्रित इलाका", + "countryCode": "देश कोड", + "dependentLocality": "निर्भर स्थान", "line1": "लाइन 1", "line2": "लाइन 2", - "postalCode": "डाक कोड", - "sortingCode": "कोड क्रमबद्ध करना", - "state": "राज्य/प्रान्त", + "postalCode": "पोस्टल कोड", + "sortingCode": "सॉर्टिंग कोड", + "state": "राज्य", "userRegistrationRequired": "उपयोगकर्ता पंजीकरण आवश्यक", - "visibleInSearch": "खोज में दृश्यमान", + "visibleInSearch": "खोज में दिखाई दे", "enterName": "नाम दर्ज करें", - "sort": "क्रम से लगाना", + "sort": "प्रकार", "Latest": "नवीनतम", - "Earliest": "जल्द से जल्द", - "noOrgErrorTitle": "संगठन नहीं मिले", - "sampleOrgDuplicate": "केवल एक नमूना संगठन को अनुमति दी गई", - "noOrgErrorDescription": "कृपया डैशबोर्ड के माध्यम से एक संगठन बनाएं", - "manageFeatures": "सुविधाओं को प्रबंधित करें", - "manageFeaturesInfo": "सृजन सफल! ", - "goToStore": "प्लगइन स्टोर पर जाएँ", + "Earliest": "सबसे पहले", + "noOrgErrorTitle": "संगठन नहीं मिला", + "sampleOrgDuplicate": "केवल एक नमूना संगठन की अनुमति है", + "noOrgErrorDescription": "कृपया डैशबोर्ड के माध्यम से संगठन बनाएं", + "manageFeatures": "विशेषताएं प्रबंधित करें", + "manageFeaturesInfo": "सफलतापूर्वक बनाया गया!", + "goToStore": "प्लगइन स्टोर पर जाएं", "enableEverything": "सब कुछ सक्षम करें", - "sampleOrgSuccess": "नमूना संगठन सफलतापूर्वक बनाया गया" + "sampleOrgSuccess": "नमूना संगठन सफलतापूर्वक बनाया गया", + "name": "नाम", + "email": "ईमेल", + "searchByName": "नाम से खोजें", + "description": "विवरण", + "location": "स्थान", + "address": "पता", + "displayImage": "छवि प्रदर्शित करें", + "filter": "फ़िल्टर", + "cancel": "रद्द करें", + "endOfResults": "परिणाम समाप्त", + "noResultsFoundFor": "कोई परिणाम नहीं मिला", + "OR": "या" }, "orgListCard": { - "manage": "प्रबंधित करना", - "sampleOrganization": "नमूना संगठन" + "manage": "प्रबंधित करें", + "sampleOrganization": "संगठन नमूना", + "admins": "प्रशासक", + "members": "सदस्य" }, "paginationList": { "rowsPerPage": "प्रति पृष्ठ पंक्तियाँ", @@ -117,104 +178,214 @@ }, "requests": { "title": "सदस्यता अनुरोध", - "sl_no": "क्र.सं. ", - "accept": "स्वीकार करना", - "reject": "अस्वीकार करना", + "sl_no": "क्रम संख्या", + "accept": "स्वीकार करें", + "reject": "अस्वीकार करें", "searchRequests": "सदस्यता अनुरोध खोजें", - "noOrgError": "संगठन नहीं मिला, कृपया डैशबोर्ड के माध्यम से एक संगठन बनाएं", + "noOrgError": "संगठन नहीं मिला, कृपया डैशबोर्ड के माध्यम से संगठन बनाएं", "noRequestsFound": "कोई सदस्यता अनुरोध नहीं मिला", "acceptedSuccessfully": "अनुरोध सफलतापूर्वक स्वीकार किया गया", - "rejectedSuccessfully": "अनुरोध सफलतापूर्वक अस्वीकार कर दिया गया", - "noOrgErrorTitle": "संगठन नहीं मिले", - "noOrgErrorDescription": "कृपया डैशबोर्ड के माध्यम से एक संगठन बनाएं" + "rejectedSuccessfully": "अनुरोध सफलतापूर्वक अस्वीकार किया गया", + "noOrgErrorTitle": "संगठन नहीं मिला", + "noOrgErrorDescription": "कृपया डैशबोर्ड के माध्यम से संगठन बनाएं", + "name": "नाम", + "email": "ईमेल", + "endOfResults": "परिणाम समाप्त", + "noResultsFoundFor": "कोई परिणाम नहीं मिला" }, "users": { - "title": "तलावा भूमिकाएँ", - "joined_organizations": "संगठनों से जुड़े", + "title": "तालावा भूमिकाएँ", + "joined_organizations": "संगठनों में शामिल हुए", "blocked_organizations": "अवरुद्ध संगठन", - "orgJoinedBy": "संगठनों से जुड़े", - "orgThatBlocked": "वे संगठन जिन्होंने अवरुद्ध किया", - "hasNotJoinedAnyOrg": "किसी भी संगठन में शामिल नहीं हुआ है", - "isNotBlockedByAnyOrg": "किसी भी संगठन द्वारा अवरुद्ध नहीं किया गया है", + "orgJoinedBy": "द्वारा शामिल संगठन", + "orgThatBlocked": "अवरुद्ध संगठन", + "hasNotJoinedAnyOrg": "किसी भी संगठन में शामिल नहीं हुआ", + "isNotBlockedByAnyOrg": "किसी भी संगठन द्वारा अवरुद्ध नहीं किया गया", "searchByOrgName": "संगठन के नाम से खोजें", - "view": "देखना", + "view": "दृश्य", "enterName": "नाम दर्ज करें", - "loadingUsers": "उपयोगकर्ता लोड हो रहे हैं...", + "loadingUsers": "उपयोगकर्ताओं को लोड कर रहा है...", "noUserFound": "कोई उपयोगकर्ता नहीं मिला", - "sort": "क्रम से लगाना", - "Newest": "नवीनतम पहले", - "Oldest": "सबसे पुराना पहले", - "noOrgError": "संगठन नहीं मिला, कृपया डैशबोर्ड के माध्यम से एक संगठन बनाएं", - "roleUpdated": "भूमिका अद्यतन की गई.", - "joinNow": "अब शामिल हों", - "visit": "मिलने जाना", - "withdraw": "चौड़ाई निकालना", - "removeUserFrom": "{{org}} से उपयोगकर्ता हटाएं", - "removeConfirmation": "क्या आप वाकई '{{org}}' संगठन से '{{name}}' को हटाना चाहते हैं?" + "sort": "प्रकार", + "Newest": "नवीनतम", + "Oldest": "सबसे पुराना", + "noOrgError": "संगठन नहीं मिला, कृपया डैशबोर्ड के माध्यम से संगठन बनाएं", + "roleUpdated": "भूमिका अपडेट की गई।", + "joinNow": "अभी शामिल हों", + "visit": "यात्रा", + "withdraw": "वापस लें", + "removeUserFrom": "{{org}} से उपयोगकर्ता को हटाएं", + "removeConfirmation": "क्या आप वाकई '{{name}}' को संगठन '{{org}}' से हटाना चाहते हैं?", + "searchByName": "नाम से खोजें", + "users": "उपयोगकर्ता", + "name": "नाम", + "email": "ईमेल", + "endOfResults": "परिणाम समाप्त", + "admin": "प्रशासक", + "superAdmin": "सुपर प्रशासक", + "user": "उपयोगकर्ता", + "filter": "फ़िल्टर", + "noResultsFoundFor": "कोई परिणाम नहीं मिला", + "talawaApiUnavailable": "तालावा एपीआई अनुपलब्ध", + "cancel": "रद्द करें", + "admins": "प्रशासक", + "members": "सदस्य", + "orgJoined": "संगठन में शामिल", + "MembershipRequestSent": "सदस्यता अनुरोध भेजा गया", + "AlreadyJoined": "पहले से शामिल", + "errorOccured": "त्रुटि हुई" }, "communityProfile": { - "title": "सामुदायिक प्रोफ़ाइल", + "title": "समुदाय प्रोफ़ाइल", "editProfile": "प्रोफ़ाइल संपादित करें", - "communityProfileInfo": "ये विवरण आपके और आपके समुदाय के सदस्यों के लिए लॉगिन/साइनअप स्क्रीन पर दिखाई देंगे", + "communityProfileInfo": "ये विवरण आपके और आपके समुदाय के सदस्यों के लॉगिन/पंजीकरण स्क्रीन पर दिखाई देंगे", "communityName": "समुदाय का नाम", - "wesiteLink": "वेबसाइट की लिंक", - "logo": "प्रतीक चिन्ह", + "wesiteLink": "वेबसाइट लिंक", + "logo": "लोगो", "social": "सोशल मीडिया लिंक", - "url": "यू आर एल दर्ज करो", - "profileChangedMsg": "प्रोफ़ाइल विवरण सफलतापूर्वक अपडेट किया गया.", - "resetData": "प्रोफ़ाइल विवरण सफलतापूर्वक रीसेट करें।" + "url": "यूआरएल दर्ज करें", + "profileChangedMsg": "प्रोफ़ाइल विवरण सफलतापूर्वक अपडेट किया गया।", + "resetData": "प्रोफ़ाइल विवरण सफलतापूर्वक रीसेट किया गया।" }, "dashboard": { "title": "डैशबोर्ड", "about": "के बारे में", - "deleteThisOrganization": "इस संगठन को हटाएँ", + "deleteThisOrganization": "इस संगठन को हटाएं", "statistics": "आंकड़े", - "posts": "पदों", - "events": "आयोजन", - "blockedUsers": "रोके गए उपयोगकर्ता", - "viewAll": "सभी को देखें", - "upcomingEvents": "आगामी कार्यक्रम", - "noUpcomingEvents": "कोई आगामी ईवेंट नहीं", + "posts": "पोस्ट", + "events": "घटनाएँ", + "blockedUsers": "अवरुद्ध उपयोगकर्ता", + "viewAll": "सभी देखें", + "upcomingEvents": "आगामी घटनाएँ", + "noUpcomingEvents": "कोई आगामी घटनाएँ नहीं हैं", "latestPosts": "नवीनतम पोस्ट", - "noPostsPresent": "कोई पोस्ट मौजूद नहीं", + "noPostsPresent": "कोई पोस्ट नहीं हैं", "membershipRequests": "सदस्यता अनुरोध", - "noMembershipRequests": "कोई सदस्यता अनुरोध मौजूद नहीं है" + "noMembershipRequests": "कोई सदस्यता अनुरोध नहीं हैं", + "location": "स्थान", + "members": "सदस्य", + "admins": "प्रशासक", + "requests": "अनुरोध", + "talawaApiUnavailable": "तालावा एपीआई अनुपलब्ध" }, "organizationPeople": { - "title": "तलवा सदस्य", + "title": "तालावा सदस्य", "filterByName": "नाम से फ़िल्टर करें", - "filterByLocation": "स्थान के अनुसार फ़िल्टर करें", - "filterByEvent": "इवेंट के अनुसार फ़िल्टर करें", + "filterByLocation": "स्थान से फ़िल्टर करें", + "filterByEvent": "घटना से फ़िल्टर करें", "searchName": "नाम दर्ज करें", - "searchevent": "इवेंट दर्ज करें", + "searchevent": "घटना दर्ज करें", "searchFullName": "पूरा नाम दर्ज करें", "people": "लोग", - "sort": "भूमिका के आधार पर खोजें", - "actions": "कार्रवाई", + "sort": "भूमिका से खोजें", + "actions": "क्रियाएँ", "addMembers": "सदस्य जोड़ें", "existingUser": "मौजूदा उपयोगकर्ता", - "newUser": "नए उपयोगकर्ता", + "newUser": "नया उपयोगकर्ता", "enterFirstName": "अपना पहला नाम दर्ज करें", "enterLastName": "अपना अंतिम नाम दर्ज करें", - "enterConfirmPassword": "पुष्टि करने के लिए अपना पासवर्ड दर्ज करें", + "enterConfirmPassword": "अपना पासवर्ड पुष्टि के लिए दर्ज करें", "organization": "संगठन", - "invalidDetailsMessage": "कृपया वैध विवरण दर्ज करें." + "invalidDetailsMessage": "कृपया मान्य विवरण दर्ज करें।", + "members": "सदस्य", + "admins": "प्रशासक", + "users": "उपयोगकर्ता", + "searchFirstName": "प्रथम नाम खोजें", + "searchLastName": "अंतिम नाम खोजें", + "firstName": "प्रथम नाम", + "lastName": "अंतिम नाम", + "emailAddress": "ईमेल पता", + "enterEmail": "ईमेल दर्ज करें", + "password": "पासवर्ड", + "enterPassword": "पासवर्ड दर्ज करें", + "confirmPassword": "पासवर्ड की पुष्टि करें", + "user": "उपयोगकर्ता", + "profile": "प्रोफ़ाइल", + "create": "बनाएं", + "cancel": "रद्द करें" + }, + "organizationTags": { + "title": "संस्थान टैग", + "createTag": "नया टैग बनाएँ", + "manageTag": "प्रबंधित करें", + "editTag": "संपादित करें", + "removeTag": "हटाएँ", + "tagDetails": "टैग विवरण", + "tagName": "नाम", + "tagType": "प्रकार", + "tagNamePlaceholder": "टैग का नाम लिखें", + "tagCreationSuccess": "नई टैग सफलतापूर्वक बनाई गई", + "tagUpdationSuccess": "टैग सफलतापूर्वक अपडेट की गई", + "tagRemovalSuccess": "टैग सफलतापूर्वक हटाई गई", + "noTagsFound": "कोई टैग नहीं मिला", + "removeUserTag": "टैग हटाएँ", + "removeUserTagMessage": "क्या आप इस टैग को हटाना चाहते हैं?", + "addChildTag": "उप-टैग जोड़ें" + }, + "manageTag": { + "title": "टैग विवरण", + "addPeopleToTag": "टैग में लोगों को जोड़ें", + "viewProfile": "देखें", + "noAssignedMembersFound": "कोई असाइन किए गए सदस्य नहीं मिले", + "unassignUserTag": "टैग को हटाएं", + "unassignUserTagMessage": "क्या आप इस उपयोगकर्ता से टैग हटाना चाहते हैं?", + "successfullyUnassigned": "उपयोगकर्ता से टैग हटा दिया गया", + "addPeople": "लोगों को जोड़ें", + "add": "जोड़ें", + "subTags": "उप-टैग्स", + "assignedToAll": "सभी को टैग असाइन किया गया", + "successfullyAssignedToPeople": "टैग सफलतापूर्वक असाइन किया गया", + "errorOccurredWhileLoadingMembers": "सदस्यों को लोड करते समय त्रुटि हुई", + "userName": "उपयोगकर्ता नाम", + "actions": "क्रियाएँ", + "noOneSelected": "कोई चयनित नहीं", + "assignToTags": "टैग्स को असाइन करें", + "removeFromTags": "टैग्स से हटाएं", + "assign": "असाइन करें", + "remove": "हटाएं", + "successfullyAssignedToTags": "सफलतापूर्वक टैग्स को असाइन किया गया", + "successfullyRemovedFromTags": "सफलतापूर्वक टैग्स से हटाया गया", + "errorOccurredWhileLoadingOrganizationUserTags": "संगठन टैग्स को लोड करते समय त्रुटि हुई", + "errorOccurredWhileLoadingSubTags": "उप-टैग लोड करते समय त्रुटि हुई", + "removeUserTag": "टैग हटाएं", + "removeUserTagMessage": "क्या आप इस टैग को हटाना चाहते हैं? यह सभी उप-टैग्स और सभी संबंधों को हटा देगा।", + "tagDetails": "टैग विवरण", + "tagName": "नाम", + "tagUpdationSuccess": "टैग सफलतापूर्वक अपडेट की गई", + "tagRemovalSuccess": "टैग सफलतापूर्वक हटाई गई", + "noTagSelected": "कोई टैग चयनित नहीं", + "changeNameToEdit": "अपडेट करने के लिए नाम बदलें", + "selectTag": "टैग चुनें", + "collapse": "संक्षिप्त करें", + "expand": "विस्तारित करें", + "tagNamePlaceholder": "टैग का नाम लिखें", + "allTags": "सभी टैग" }, "userListCard": { "addAdmin": "व्यवस्थापक जोड़ें", - "addedAsAdmin": "उपयोगकर्ता को व्यवस्थापक के रूप में जोड़ा गया है." + "addedAsAdmin": "उपयोगकर्ता को व्यवस्थापक के रूप में जोड़ा गया है.", + "joined": "शामिल हुए", + "talawaApiUnavailable": "Talawa API अनुपलब्ध" }, "orgAdminListCard": { "remove": "निकालना", "removeAdmin": "व्यवस्थापक हटाएँ", "removeAdminMsg": "क्या आप इस व्यवस्थापक को हटाना चाहते हैं?", - "adminRemoved": "व्यवस्थापक को हटा दिया गया है." + "adminRemoved": "व्यवस्थापक को हटा दिया गया है.", + "joined": "शामिल हुए", + "no": "नहीं", + "yes": "हाँ", + "talawaApiUnavailable": "Talawa API अनुपलब्ध" }, "orgPeopleListCard": { "remove": "निकालना", "removeMember": "सदस्य हटाएँ", "removeMemberMsg": "क्या आप इस सदस्य को हटाना चाहते हैं?", - "memberRemoved": "सदस्य को हटा दिया गया है" + "memberRemoved": "सदस्य को हटा दिया गया है", + "joined": "शामिल हुए", + "no": "नहीं", + "yes": "हाँ", + "talawaApiUnavailable": "Talawa API अनुपलब्ध" }, "organizationEvents": { "title": "आयोजन", @@ -245,7 +416,14 @@ "never": "कभी नहीं", "on": "पर", "after": "बाद", - "occurences": "घटनाओं" + "occurences": "घटनाओं", + "events": "कार्यक्रम", + "description": "विवरण", + "location": "स्थान", + "startDate": "प्रारंभ तिथि", + "endDate": "समाप्ति तिथि", + "talawaApiUnavailable": "Talawa API अनुपलब्ध", + "done": "पूर्ण" }, "organizationActionItems": { "actionItemCategory": "कार्य आइटम श्रेणी", @@ -256,7 +434,6 @@ "assignmentDate": "असाइनमेंट दिनांक", "active": "सक्रिय", "clearFilters": "फ़िल्टर साफ़ करें", - "completed": "पुरा होना।", "completionDate": "पूरा करने की तिथि", "createActionItem": "कार्रवाई आइटम बनाएं", "deleteActionItem": "क्रिया आइटम हटाएँ", @@ -267,6 +444,7 @@ "editActionItem": "क्रिया आइटम संपादित करें", "isCompleted": "पुरा होना।", "latest": "नवीनतम", + "makeActive": "सक्रिय", "noActionItems": "कोई एक्शन आइटम नहीं", "options": "विकल्प", "preCompletionNotes": "समापन पूर्व नोट्स", @@ -280,7 +458,18 @@ "successfulCreation": "कार्रवाई आइटम सफलतापूर्वक बनाया गया", "successfulUpdation": "कार्रवाई आइटम सफलतापूर्वक अपडेट किया गया", "successfulDeletion": "कार्रवाई आइटम सफलतापूर्वक हटा दिया गया", - "title": "एक्शन आइटम्स" + "title": "एक्शन आइटम्स", + "category": "श्रेणी", + "allotedHours": "आवंटित घंटे", + "latestDueDate": "सबसे अधिक नियत तिथि", + "earliestDueDate": "सबसे पहले की नियत तिथि", + "updateActionItem": "कार्य आइटम अपडेट करें", + "noneUpdated": "कोई फ़ील्ड अपडेट नहीं किया गया", + "updateStatusMsg": "क्या आप वाकई इस कार्य आइटम को लंबित के रूप में चिह्नित करना चाहते हैं?", + "close": "बंद करें", + "eventActionItems": "कार्यक्रम कार्रवाई आइटम", + "no": "नहीं", + "yes": "हाँ" }, "organizationAgendaCategory": { "agendaCategoryDetails": "एजेंडा श्रेणी विवरण", @@ -299,6 +488,40 @@ "deleteAgendaCategory": "एजेंडा श्रेणी हटाएं", "deleteAgendaCategoryMsg": "क्या आप इस एजेंडा श्रेणी को हटाना चाहते हैं?" }, + "agendaItems": { + "agendaItemDetails": "एजेंडा आइटम विवरण", + "updateAgendaItem": "एजेंडा आइटम अपडेट करें", + "title": "शीर्षक", + "enterTitle": "शीर्षक दर्ज करें", + "sequence": "क्रम", + "description": "विवरण", + "enterDescription": "विवरण दर्ज करें", + "category": "एजेंडा श्रेणी", + "attachments": "संलग्नक", + "attachmentLimit": "10MB तक कोई भी छवि फ़ाइल या वीडियो फ़ाइल जोड़ें", + "fileSizeExceedsLimit": "फ़ाइल का आकार सीमा 10MB से अधिक है", + "urls": "URL", + "url": "URL में लिंक जोड़ें", + "enterUrl": "https://example.com", + "invalidUrl": "कृपया एक वैध URL दर्ज करें", + "link": "लिंक", + "createdBy": "बनाया गया द्वारा", + "regular": "नियमित", + "note": "नोट", + "duration": "अवधि", + "enterDuration": "मिमी:से", + "options": "विकल्प", + "createAgendaItem": "एजेंडा आइटम बनाएं", + "noAgendaItems": "कोई एजेंडा आइटम नहीं", + "selectAgendaItemCategory": "एजेंडा आइटम श्रेणी चुनें", + "update": "अपडेट करें", + "delete": "हटाएं", + "agendaItemCreated": "एजेंडा आइटम सफलतापूर्वक बनाया गया", + "agendaItemUpdated": "एजेंडा आइटम सफलतापूर्वक अपडेट किया गया", + "agendaItemDeleted": "एजेंडा आइटम सफलतापूर्वक हटा दिया गया", + "deleteAgendaItem": "एजेंडा आइटम हटाएं", + "deleteAgendaItemMsg": "क्या आप इस एजेंडा आइटम को हटाना चाहते हैं?" + }, "eventListCard": { "deleteEvent": "ईवेंट हटाएँ", "deleteEventMsg": "क्या आप इस ईवेंट को हटाना चाहते हैं?", @@ -325,62 +548,68 @@ "never": "कभी नहीं", "on": "पर", "after": "बाद", - "occurences": "घटनाओं" + "occurences": "घटनाओं", + "location": "स्थान", + "no": "नहीं", + "yes": "हाँ", + "description": "विवरण", + "startDate": "प्रारंभ तिथि", + "endDate": "समाप्ति तिथि", + "registerEvent": "कार्यक्रम के लिए पंजीकरण करें", + "close": "बंद करें", + "talawaApiUnavailable": "Talawa API अनुपलब्ध", + "done": "समाप्त" }, "funds": { "title": "फंड", - "createFund": "फंड बनाएं", + "createFund": "फंड बनाएँ", "fundName": "फंड का नाम", - "fundId": "फंड आईडी", - "fundOptions": "Opitons", - "noFunds": "कोई फंड नहीं मिला", - "fundDetails": "फंड विवरण", - "taxDeductible": "कर छूट", - "enterfundName": "फंड का नाम दर्ज करें", - "enterfundId": "फंड आईडी दर्ज करें", - "default": "डिफ़ॉल्ट फंड", - "archived": "संग्रहीत", - "nonArchive": "गैर-अभिलेखित", - "fundCreate": "फंड बनाएं", - "fundUpdate": "अद्यतन निधि", - "fundDelete": "फ़ंड हटाएँ", - "manageFund": "फंड का प्रबंधन करें", - "searchFullName": "नाम से खोजें", + "fundId": "फंड (संदर्भ) आईडी", + "taxDeductible": "कर ड्यूटी कटाई", + "default": "डिफ़ॉल्ट", + "archived": "आर्काइव", + "fundCreate": "फंड बनाएँ", + "fundUpdate": "फंड अपडेट करें", + "fundDelete": "फंड को हटाएँ", + "searchByName": "नाम से खोजें", "noFundsFound": "कोई फंड नहीं मिला", - "createdBy": "के द्वारा बनाई गई", - "createdOn": "पर बनाया", + "createdBy": "द्वारा बनाया गया", + "createdOn": "पर बनाया गया", "status": "स्थिति", - "archiveFund": "पुरालेख कोष", - "archiveFundMsg": "इस फंड को संग्रहित करने पर इसे फंड सूची से हटा दिया जाएगा। इस कार्रवाई को पूर्ववत किया जा सकता है", "fundCreated": "फंड सफलतापूर्वक बनाया गया", "fundUpdated": "फंड सफलतापूर्वक अपडेट किया गया", - "fundDeleted": "फंड सफलतापूर्वक हटा दिया गया", - "fundArchived": "निधि सफलतापूर्वक संग्रहित की गई", - "fundUnarchived": "फंड सफलतापूर्वक संग्रहित किया गया", - "deleteFundMsg": "क्या आप इस फंड को हटाना चाहते हैं?" + "fundDeleted": "फंड सफलतापूर्वक हटाया गया", + "deleteFundMsg": "क्या आप वाकई इस फंड को हटाना चाहते हैं?", + "createdLatest": "सबसे पहले बनाया", + "createdEarliest": "सबसे जल्दी बनाया", + "viewCampaigns": "कैम्पेंस देखें" }, "fundCampaign": { - "title": "धन उगाही अभियान", - "campaignName": "अभियान का नाम", + "title": "फंडरेजिंग कैंपेन", + "campaignName": "कैंपेन का नाम", "campaignOptions": "विकल्प", - "fundingGoal": "वित्त पोषण लक्ष्य", - "addCampaign": "अभियान जोड़ें", - "createdCampaign": "अभियान सफलतापूर्वक बनाया गया", - "updatedCampaign": "अभियान सफलतापूर्वक अपडेट किया गया", - "deletedCampaign": "अभियान सफलतापूर्वक हटा दिया गया", - "deleteCampaignMsg": "क्या आप वाकई इस अभियान को हटाना चाहते हैं?", - "noCampaigns": "कोई अभियान नहीं मिला", - "createCampaign": "फंड अभियान बनाएं", - "updateCampaign": "अद्यतन निधि अभियान", - "manageCampaign": "फंड अभियान प्रबंधित करें", - "deleteCampaign": "फ़ंड अभियान हटाएँ", + "fundingGoal": "फंडिंग उद्देश्य", + "addCampaign": "कैंपेन जोड़ें", + "createdCampaign": "कैंपेन सफलतापूर्वक बनाई गई", + "updatedCampaign": "कैंपेन सफलतापूर्वक अपडेट की गई", + "deletedCampaign": "कैंपेन सफलतापूर्वक हटा दी गई", + "deleteCampaignMsg": "क्या आप वाकई इस कैंपेन को हटाना चाहते हैं?", + "noCampaigns": "कोई कैंपेन नहीं मिली", + "createCampaign": "कैंपेन बनाएँ", + "updateCampaign": "कैंपेन अपडेट करें", + "deleteCampaign": "कैंपेन को हटाएं", "currency": "मुद्रा", - "selectCurrency": "मुद्रा चुनें", - "searchFullName": "नाम से खोजें" + "selectCurrency": "मुद्रा का चयन करें", + "searchFullName": "नाम से खोजें", + "viewPledges": "प्लेज देखें", + "noCampaignsFound": "कोई कैंपेन नहीं मिली", + "latestEndDate": "अंतिम समाप्ति तिथि", + "earliestEndDate": "सबसे पहली समाप्ति तिथि", + "lowestGoal": "सबसे कम उद्देश्य", + "highestGoal": "सबसे ऊंचा उद्देश्य" }, "pledges": { "title": "निधि अभियान प्रतिज्ञाएँ", - "volunteers": "स्वयंसेवकों", "pledgeAmount": "प्रतिज्ञा राशि", "pledgeOptions": "विकल्प", "pledgeCreated": "प्रतिज्ञा सफलतापूर्वक बनाई गई", @@ -396,12 +625,18 @@ "editPledge": "प्रतिज्ञा संपादित करें", "deletePledgeMsg": "क्या आप वाकई इस प्रतिज्ञा को हटाना चाहते हैं?", "noPledges": "कोई प्रतिज्ञा नहीं मिली", - "sort": "क्रमबद्ध करें", - "searchVolunteer": "स्वयंसेवक द्वारा खोजें", + "searchPledger": "प्लेजर्स के द्वारा खोजें", "highestAmount": "सबसे अधिक राशि", "lowestAmount": "सबसे कम राशि", "latestEndDate": "नवीनतम समाप्ति तिथि", - "earliestEndDate": "सबसे प्रारंभिक समाप्ति तिथि" + "earliestEndDate": "सबसे प्रारंभिक समाप्ति तिथि", + "campaigns": "अभियान", + "pledges": "प्रतिज्ञाएँ", + "endsOn": "पर समाप्त होता है", + "raisedAmount": "उठाया गया राशि", + "pledgedAmount": "प्रतिबद्ध राशि", + "startDate": "प्रारंभ तिथि", + "endDate": "समाप्ति तिथि" }, "orgPost": { "title": "पदों", @@ -429,7 +664,8 @@ "postCreatedSuccess": "बधाई हो! ", "pinPost": "पिन पद", "Next": "अगला पृष्ठ", - "Previous": "पिछला पृष्ठ" + "Previous": "पिछला पृष्ठ", + "cancel": "रद्द करें" }, "postNotFound": { "post": "डाक", @@ -444,7 +680,8 @@ "user not found!": "उपयोगकर्ता नहीं मिला!", "member not found!": "सदस्य अनुपस्थित!", "admin not found!": "व्यवस्थापक नहीं मिला!", - "roles not found!": "भूमिकाएँ नहीं मिलीं!" + "roles not found!": "भूमिकाएँ नहीं मिलीं!", + "user": "उपयोगकर्ता" }, "orgPostCard": { "author": "लेखक", @@ -463,7 +700,12 @@ "postDeleted": "पोस्ट सफलतापूर्वक हटा दी गई.", "postUpdated": "पोस्ट सफलतापूर्वक अपडेट किया गया.", "tag": " आपका ब्राउज़र में वीडियो टैग समर्थित नहीं है", - "pin": "पिन पद" + "pin": "पिन पद", + "edit": "संपादित करें", + "no": "नहीं", + "yes": "हाँ", + "close": "बंद करें", + "talawaApiUnavailable": "Talawa API अनुपलब्ध" }, "blockUnblockUser": { "title": "उपयोगकर्ता को ब्लॉक/अनब्लॉक करें", @@ -479,13 +721,19 @@ "blockedUsers": "रोके गए उपयोगकर्ता", "searchByFirstName": "प्रथम नाम से खोजें", "searchByLastName": "अंतिम नाम से खोजें", - "noSpammerFound": "कोई स्पैमर नहीं मिला" + "noSpammerFound": "कोई स्पैमर नहीं मिला", + "searchByName": "नाम से खोजें", + "name": "नाम", + "email": "ईमेल", + "talawaApiUnavailable": "Talawa API अनुपलब्ध", + "noResultsFoundFor": "के लिए कोई परिणाम नहीं मिला" }, "eventManagement": { "title": "इवेंट मैनेजमेंट", "dashboard": "डैशबोर्ड", "registrants": "कुलसचिव", "eventActions": "घटना क्रियाएँ", + "eventAgendas": "इवेंट एजेंडा", "eventStats": "घटना सांख्यिकी", "to": "को" }, @@ -503,7 +751,10 @@ "errorSendingMail": "मेल भेजने में त्रुटि.", "passwordMismatches": "पासवर्ड और पासवर्ड बेमेल होने की पुष्टि करें।", "passwordChanges": "पासवर्ड सफलतापूर्वक बदल गया.", - "OTPsent": "ओटीपी आपके पंजीकृत ईमेल पर भेजा जाता है।" + "OTPsent": "ओटीपी आपके पंजीकृत ईमेल पर भेजा जाता है।", + "forgotPassword": "पासवर्ड भूल गए", + "password": "पासवर्ड", + "talawaApiUnavailable": "Talawa API अनुपलब्ध" }, "pageNotFound": { "404": "404", @@ -533,15 +784,16 @@ "amount": "मात्रा" }, "orgSettings": { - "title": "समायोजन", + "title": "सेटिंग्स", "general": "सामान्य", - "actionItemCategories": "कार्रवाई आइटम श्रेणियाँ", - "updateOrganization": "संगठन अद्यतन करें", + "actionItemCategories": "कार्य आइटम श्रेणियाँ", + "updateOrganization": "संगठन अपडेट करें", "seeRequest": "अनुरोध देखें", "noData": "कोई डेटा नहीं", - "otherSettings": "अन्य सेटिंग", + "otherSettings": "अन्य सेटिंग्स", "changeLanguage": "भाषा बदलें", - "manageCustomFields": "कस्टम फ़ील्ड प्रबंधित करें" + "manageCustomFields": "कस्टम फ़ील्ड प्रबंधित करें", + "agendaItemCategories": "एजेंडा आइटम श्रेणियाँ" }, "deleteOrg": { "deleteOrganization": "संगठन हटाएँ", @@ -549,16 +801,30 @@ "deleteMsg": "क्या आप इस संगठन को हटाना चाहते हैं?", "confirmDelete": "हटाने की पुष्टि करें", "longDelOrgMsg": "संगठन हटाएं बटन पर क्लिक करने से संगठन अपने ईवेंट, टैग और सभी संबंधित डेटा के साथ स्थायी रूप से हटा दिया जाएगा।", - "successfullyDeletedSampleOrganization": "नमूना संगठन सफलतापूर्वक हटा दिया गया" + "successfullyDeletedSampleOrganization": "नमूना संगठन सफलतापूर्वक हटा दिया गया", + "cancel": "रद्द करें" }, "userUpdate": { "appLanguageCode": "डिफ़ॉल्ट भाषा", - "userType": "उपयोगकर्ता का प्रकार" + "userType": "उपयोगकर्ता का प्रकार", + "firstName": "प्रथम नाम", + "lastName": "अंतिम नाम", + "email": "ईमेल", + "password": "पासवर्ड", + "admin": "प्रशासक", + "superAdmin": "सुपर प्रशासक", + "displayImage": "प्रदर्शन छवि", + "saveChanges": "परिवर्तन सहेजें", + "cancel": "रद्द करें" }, "userPasswordUpdate": { "previousPassword": "पिछला पासवर्ड", "newPassword": "नया पासवर्ड", - "confirmNewPassword": "नए पासवर्ड की पुष्टि करें" + "confirmNewPassword": "नए पासवर्ड की पुष्टि करें", + "passCantBeEmpty": "पासवर्ड खाली नहीं हो सकता", + "passNoMatch": "नया पासवर्ड और पुष्टि पासवर्ड मेल नहीं खाते।", + "saveChanges": "परिवर्तन सहेजें", + "cancel": "रद्द करें" }, "orgDelete": { "deleteOrg": "संगठन हटाएं" @@ -566,7 +832,9 @@ "membershipRequest": { "accept": "स्वीकार करना", "reject": "अस्वीकार करना", - "memberAdded": "यह स्वीकृत है" + "memberAdded": "यह स्वीकृत है", + "joined": "शामिल हुए", + "talawaApiUnavailable": "Talawa API अनुपलब्ध" }, "orgUpdate": { "city": "शहर", @@ -580,7 +848,15 @@ "userRegistrationRequired": "उपयोगकर्ता पंजीकरण आवश्यक", "isVisibleInSearch": "खोज में दृश्यमान", "enterNameOrganization": "संगठन का नाम दर्ज करें", - "successfulUpdated": "संगठन सफलतापूर्वक अद्यतन किया गया" + "successfulUpdated": "संगठन सफलतापूर्वक अद्यतन किया गया", + "name": "नाम", + "description": "विवरण", + "location": "स्थान", + "address": "पता", + "displayImage": "प्रदर्शन छवि", + "saveChanges": "परिवर्तन सहेजें", + "cancel": "रद्द करें", + "talawaApiUnavailable": "Talawa API अनुपलब्ध" }, "addOnRegister": { "addNew": "नया जोड़ो", @@ -590,7 +866,9 @@ "pluginDesc": "प्लगइन विवरण", "pName": "उदाहरणार्थ: दान", "cName": "उदाहरण: जॉन डो", - "pDesc": "यह प्लगइन यूआई को सक्षम बनाता है" + "pDesc": "यह प्लगइन यूआई को सक्षम बनाता है", + "close": "बंद करें", + "register": "पंजीकरण करें" }, "addOnStore": { "title": "स्टोर पर जोड़ें", @@ -601,7 +879,8 @@ "pHeading": "प्लग-इन", "install": "स्थापित", "available": "उपलब्ध", - "pMessage": "प्लगइन मौजूद नहीं है" + "pMessage": "प्लगइन मौजूद नहीं है", + "filter": "फ़िल्टर" }, "addOnEntry": { "enable": "सक्रिय", @@ -646,14 +925,32 @@ "membershipRequests": "सदस्यता अनुरोध", "adminForEvents": "घटनाओं के लिए व्यवस्थापक", "addedAsAdmin": "उपयोगकर्ता को व्यवस्थापक के रूप में जोड़ा गया है.", - "userType": "उपयोगकर्ता का प्रकार" + "userType": "उपयोगकर्ता का प्रकार", + "email": "ईमेल", + "displayImage": "प्रदर्शन छवि", + "address": "पता", + "delete": "हटाएं", + "saveChanges": "परिवर्तन सहेजें", + "joined": "शामिल हुए", + "talawaApiUnavailable": "Talawa API अनुपलब्ध" + }, + "people": { + "title": "लोग", + "searchUsers": "उपयोगकर्ताओं को खोजें" }, "userLogin": { "login": "लॉग इन करें", "loginIntoYourAccount": "अपने खाते में लॉगिन करें", "invalidDetailsMessage": "कृपया एक वैध ईमेल और पासवर्ड दर्ज करें।", "notAuthorised": "क्षमा मांगना! ", - "invalidCredentials": "दर्ज किए गए क्रेडेंशियल ग़लत हैं. " + "invalidCredentials": "दर्ज किए गए क्रेडेंशियल ग़लत हैं. ", + "forgotPassword": "पासवर्ड भूल गए", + "emailAddress": "ईमेल पता", + "enterEmail": "ईमेल दर्ज करें", + "password": "पासवर्ड", + "enterPassword": "पासवर्ड दर्ज करें", + "register": "पंजीकरण करें", + "talawaApiUnavailable": "Talawa API अनुपलब्ध" }, "userRegister": { "enterFirstName": "अपना पहला नाम दर्ज करें", @@ -663,7 +960,16 @@ "login": "लॉग इन करें", "afterRegister": "पंजीकरण सफलतापूर्वक हो गया है। ", "passwordNotMatch": "पासवर्ड मेल नहीं खाता. ", - "invalidDetailsMessage": "कृपया वैध विवरण दर्ज करें." + "invalidDetailsMessage": "कृपया वैध विवरण दर्ज करें.", + "register": "पंजीकरण करें", + "firstName": "प्रथम नाम", + "lastName": "अंतिम नाम", + "emailAddress": "ईमेल पता", + "enterEmail": "ईमेल दर्ज करें", + "password": "पासवर्ड", + "enterPassword": "पासवर्ड दर्ज करें", + "confirmPassword": "पासवर्ड की पुष्टि करें", + "talawaApiUnavailable": "Talawa API अनुपलब्ध" }, "userNavbar": { "talawa": "तलावा", @@ -672,7 +978,10 @@ "events": "आयोजन", "chat": "बात करना", "donate": "दान करें", - "language": "भाषा" + "language": "भाषा", + "settings": "समायोजन", + "logout": "लॉग आउट करें", + "close": "बंद करें" }, "userOrganizations": { "allOrganizations": "सभी संगठन", @@ -681,7 +990,11 @@ "selectOrganization": "एक संगठन चुनें", "searchUsers": "उपयोगकर्ता खोजें", "nothingToShow": "यहां दिखाने के लिए कुछ भी नहीं है.", - "organizations": "संगठनों" + "organizations": "संगठनों", + "search": "खोजें", + "filter": "फ़िल्टर", + "searchByName": "नाम से खोजें", + "searchOrganizations": "संगठनों खोजें" }, "userSidebarOrg": { "yourOrganizations": "आपके संगठन", @@ -689,22 +1002,32 @@ "viewAll": "सभी को देखें", "talawaUserPortal": "तलावा उपयोगकर्ता पोर्टल", "my organizations": "मेरे संगठन", - "communityProfile": "सामुदायिक प्रोफ़ाइल" + "communityProfile": "सामुदायिक प्रोफ़ाइल", + "users": "उपयोगकर्ता", + "requests": "अनुरोध", + "logout": "लॉग आउट", + "settings": "सेटिंग्स", + "chat": "चैट", + "menu": "मेनू" }, "organizationSidebar": { "viewAll": "सभी को देखें", "events": "आयोजन", "noEvents": "दिखाने के लिए कोई ईवेंट नहीं", - "noMembers": "दिखाने के लिए कोई सदस्य नहीं" + "noMembers": "दिखाने के लिए कोई सदस्य नहीं", + "members": "सदस्य" }, "postCard": { "likes": "पसंद है", - "comments": "टिप्पणियाँ" + "comments": "टिप्पणियाँ", + "viewPost": "पोस्ट देखें", + "editPost": "पोस्ट संपादित करें", + "postedOn": "{{date}} को पोस्ट किया गया" }, "home": { + "title": "पदों", "posts": "पदों", "post": "डाक", - "title": "शीर्षक", "textArea": "आपके मन में कुछ है?", "feed": "खिलाना", "loading": "लोड हो रहा है", @@ -716,7 +1039,8 @@ "startPost": "एक पोस्ट प्रारंभ करें", "media": "मिडिया", "event": "आयोजन", - "article": "लेख" + "article": "लेख", + "postNowVisibleInFeed": "पोस्ट अब फीड में दिखाई दे रहा है" }, "settings": { "noeventsAttended": "कोई कार्यक्रम में उपस्थित नहीं", @@ -752,7 +1076,7 @@ "widowed": "विधवा", "divorced": "तलाकशुदा", "engaged": "काम में लगा हुआ", - "seperated": "विभाजित", + "separated": "विभाजित", "grade1": "ग्रेड 1", "grade2": "ग्रेड 2", "grade3": "ग्रेड 3", @@ -772,9 +1096,18 @@ "fullTime": "पूरा समय", "partTime": "पार्ट टाईम", "selectCountry": "कोई देश चुनें", - "enterState": "शहर या राज्य दर्ज करें" + "enterState": "शहर या राज्य दर्ज करें", + "settings": "समायोजन", + "firstName": "प्रथम नाम", + "lastName": "अंतिम नाम", + "emailAddress": "ईमेल पता", + "displayImage": "प्रदर्शन छवि", + "address": "पता", + "saveChanges": "परिवर्तन सहेजें", + "joined": "शामिल हुए" }, "donate": { + "title": "दान", "donations": "दान", "searchDonations": "दान खोजें", "donateForThe": "के लिए दान करें", @@ -782,9 +1115,14 @@ "yourPreviousDonations": "आपका पिछला दान", "donate": "दान करें", "nothingToShow": "यहां दिखाने के लिए कुछ भी नहीं है.", - "success": "दान सफल" + "success": "दान सफल", + "invalidAmount": "कृपया दान राशि के लिए संख्यात्मक मान दर्ज करें.", + "donationAmountDescription": "कृपया दान राशि के लिए संख्यात्मक मान दर्ज करें.", + "donationOutOfRange": "दान राशि {{min}} और {{max}} के बीच होनी चाहिए.", + "donateTo": "दान करें" }, "userEvents": { + "title": "ईवेंट", "nothingToShow": "यहां दिखाने के लिए कुछ भी नहीं है.", "createEvent": "कार्यक्रम बनाएँ", "recurring": "पुनरावर्ती ईवेंट", @@ -802,13 +1140,22 @@ "publicEvent": "सार्वजनिक है", "registerable": "पंजीकरण योग्य है", "monthlyCalendarView": "मासिक कैलेंडर", - "yearlyCalendarView": "वार्षिक कैलेंडर" + "yearlyCalendarView": "वार्षिक कैलेंडर", + "search": "खोजें", + "cancel": "रद्द करें", + "create": "बनाएं", + "eventDescription": "कार्यक्रम विवरण", + "eventLocation": "कार्यक्रम स्थान", + "startDate": "प्रारंभ तिथि", + "endDate": "समाप्ति तिथि" }, "userEventCard": { "starts": "प्रारंभ होगा", "ends": "समाप्त होता है", "creator": "निर्माता", - "alreadyRegistered": "पहले से ही पंजीकृत" + "alreadyRegistered": "पहले से ही पंजीकृत", + "location": "स्थान", + "register": "पंजीकरण करें" }, "advertisement": { "title": "विज्ञापनों", @@ -830,11 +1177,24 @@ "deleteAdvertisement": "विज्ञापन हटाएँ", "deleteAdvertisementMsg": "क्या आप यह विज्ञापन हटाना चाहते हैं?", "view": "देखना", - "editAdvertisement": "विज्ञापन संपादित करें" + "editAdvertisement": "विज्ञापन संपादित करें", + "advertisementDeleted": "विज्ञापन सफलतापूर्वक हटाया गया।", + "endDateGreaterOrEqual": "समाप्ति तिथि प्रारंभ तिथि से अधिक या उसके बराबर होनी चाहिए", + "advertisementCreated": "विज्ञापन सफलतापूर्वक बनाया गया।", + "pHeading": "विज्ञापन शीर्षक", + "delete": "हटाएं", + "close": "बंद करें", + "no": "नहीं", + "yes": "हाँ", + "edit": "संपादित करें", + "saveChanges": "परिवर्तन सहेजें", + "endOfResults": "परिणाम समाप्त" }, "userChat": { "chat": "बात करना", - "contacts": "संपर्क" + "contacts": "संपर्क", + "search": "खोज", + "messages": "संदेश" }, "userChatRoom": { "selectContact": "बातचीत शुरू करने के लिए एक संपर्क चुनें", @@ -852,20 +1212,28 @@ "String": "स्ट्रिंग", "Boolean": "बूलियन", "Date": "तारीख", - "Number": "संख्या" + "Number": "संख्या", + "saveChanges": "परिवर्तन सहेजें" }, "orgActionItemCategories": { "enableButton": "सक्षम", "disableButton": "अक्षम करना", "updateActionItemCategory": "अद्यतन", "actionItemCategoryName": "नाम", - "actionItemCategoryDetails": "कार्य आइटम श्रेणी विवरण", + "categoryDetails": "श्रेणी विवरण", "enterName": "नाम दर्ज करें", "successfulCreation": "कार्रवाई आइटम श्रेणी सफलतापूर्वक बनाई गई", "successfulUpdation": "कार्रवाई आइटम श्रेणी सफलतापूर्वक अपडेट की गई", "sameNameConflict": "अपडेट करने के लिए कृपया नाम बदलें", "categoryEnabled": "कार्य आइटम श्रेणी सक्षम", - "categoryDisabled": "कार्रवाई आइटम श्रेणी अक्षम" + "categoryDisabled": "कार्रवाई आइटम श्रेणी अक्षम", + "noActionItemCategories": "कोई कार्रवाई आइटम श्रेणी नहीं", + "status": "स्थिति", + "categoryDeleted": "कार्रवाई आइटम श्रेणी सफलतापूर्वक हटा दी गई", + "deleteCategory": "श्रेणी हटाएं", + "deleteCategoryMsg": "क्या आप वाकई इस कार्रवाई आइटम श्रेणी को हटाना चाहते हैं?", + "createButton": "बटन बनाएं", + "editButton": "संपादित बटन" }, "organizationVenues": { "title": "स्थानों", @@ -889,7 +1257,12 @@ "view": "देखना", "venueTitleError": "स्थान का शीर्षक खाली नहीं हो सकता!", "venueCapacityError": "क्षमता एक धनात्मक संख्या होनी चाहिए!", - "searchBy": "खोज से" + "searchBy": "खोज से", + "description": "विवरण", + "edit": "संपादित करें", + "delete": "हटाएं", + "name": "नाम", + "desc": "विवरण" }, "addMember": { "title": "सदस्य जोड़ें", @@ -903,7 +1276,18 @@ "organization": "संगठन", "invalidDetailsMessage": "कृपया सभी आवश्यक विवरण प्रदान करें।", "passwordNotMatch": "सांकेतिक शब्द मेल नहीं खाते।", - "addMember": "सदस्य जोड़ें" + "addMember": "सदस्य जोड़ें", + "firstName": "प्रथम नाम", + "lastName": "अंतिम नाम", + "emailAddress": "ईमेल पता", + "enterEmail": "ईमेल दर्ज करें", + "password": "पासवर्ड", + "enterPassword": "पासवर्ड दर्ज करें", + "confirmPassword": "पासवर्ड की पुष्टि करें", + "cancel": "रद्द करें", + "create": "बनाएं", + "user": "उपयोगकर्ता", + "profile": "प्रोफ़ाइल" }, "eventActionItems": { "title": "एक्शन आइटम्स", @@ -911,8 +1295,8 @@ "actionItemCategory": "कार्य आइटम श्रेणी", "selectActionItemCategory": "एक क्रिया आइटम श्रेणी का चयन करें", "selectAssignee": "एक समनुदेशिती का चयन करें", - "preCompletionNotes": "समापन पूर्व नोट्स", - "postCompletionNotes": "समापन के बाद के नोट्स", + "preCompletionNotes": "टिप्पणियाँ", + "postCompletionNotes": "समापन नोट्स", "actionItemDetails": "कार्रवाई मद विवरण", "dueDate": "नियत तारीख", "completionDate": "पूरा करने की तिथि", @@ -923,6 +1307,45 @@ "successfulCreation": "कार्रवाई आइटम सफलतापूर्वक बनाया गया", "successfulUpdation": "कार्रवाई आइटम सफलतापूर्वक अपडेट किया गया", "notes": "टिप्पणियाँ", - "save": "बचाना" + "assignee": "संपत्ति-भागी", + "assigner": "असाइनर", + "assignmentDate": "असाइनमेंट तिथि", + "status": "स्थिति", + "actionItemActive": "सक्रिय", + "actionItemStatus": "कार्रवाई आइटम स्थिति", + "actionItemCompleted": "कार्रवाई आइटम पूर्ण हुआ", + "markCompletion": "पूर्णता को चिह्नित करें", + "save": "बचाना", + "yes": "हाँ", + "no": "नहीं" + }, + "checkIn": { + "errorCheckingIn": "चेक-इन में त्रुटि", + "checkedInSuccessfully": "सफलतापूर्वक चेक-इन किया गया" + }, + "eventRegistrantsModal": { + "errorAddingAttendee": "उपस्थित होने वाले को जोड़ने में त्रुटि", + "errorRemovingAttendee": "उपस्थित होने वाले को हटाने में त्रुटि" + }, + "userCampaigns": { + "title": "धन उगाहने के अभियान", + "searchByName": "नाम से खोजें...", + "searchBy": "द्वारा खोजें", + "pledgers": "प्रतिज्ञाकर्ता", + "campaigns": "अभियान", + "myPledges": "मेरी प्रतिज्ञाएँ", + "lowestAmount": "सबसे कम राशि", + "highestAmount": "सबसे अधिक राशि", + "lowestGoal": "सबसे कम लक्ष्य", + "highestGoal": "सबसे बड़ा लक्ष्य", + "latestEndDate": "सबसे अंतिम समाप्ति तिथि", + "earliestEndDate": "सबसे पहले समाप्ति तिथि", + "addPledge": "प्रतिज्ञा जोड़ें", + "viewPledges": "प्रतिज्ञाएँ देखें", + "noPledges": "कोई प्रतिज्ञा नहीं मिली", + "noCampaigns": "कोई अभियान नहीं मिला" + }, + "userPledges": { + "title": "मेरी प्रतिज्ञाएँ" } } diff --git a/public/locales/sp/common.json b/public/locales/sp/common.json index d9d1663f7d..d0b918c925 100644 --- a/public/locales/sp/common.json +++ b/public/locales/sp/common.json @@ -76,5 +76,22 @@ "noFiltersApplied": "No se aplicaron filtros", "manage": "Administrar", "searchResultsFor": "Resultados de búsqueda para {{text}}", - "none": "Ninguno" + "none": "Ninguno", + "sort": "Ordenar", + "Donate": "Donar", + "addedSuccessfully": "{{item}} agregado con éxito", + "updatedSuccessfully": "{{item}} actualizado con éxito", + "removedSuccessfully": "{{item}} eliminado con éxito", + "successfullyUpdated": "Actualizado con éxito", + "sessionWarning": "Su sesión expirará pronto debido a la inactividad. Por favor, interactúe con la página para extender su sesión.", + "sessionLogOut": "Su sesión ha expirado debido a la inactividad. Por favor, inicie sesión nuevamente para continuar.", + "all": "Todos", + "active": "Activo", + "disabled": "Deshabilitado", + "pending": "Pendiente", + "completed": "Completado", + "late": "Tarde", + "createdLatest": "Creado más reciente", + "createdEarliest": "Creado más temprano", + "searchBy": "Buscar por {{item}}" } diff --git a/public/locales/sp/errors.json b/public/locales/sp/errors.json index 90b2acca9f..39b579abac 100644 --- a/public/locales/sp/errors.json +++ b/public/locales/sp/errors.json @@ -5,5 +5,7 @@ "notAuthorised": "Sorry! you are not Authorised!", "errorSendingMail": "Error sending mail", "emailNotRegistered": "Email not registered", - "notFoundMsg": "Oops! The Page you requested was not found!" + "notFoundMsg": "Oops! The Page you requested was not found!", + "errorOccurredCouldntCreate": "Ocurrió un error. No se pudo crear {{entity}}", + "errorLoading": "Ocurrió un error al cargar los datos de {{entity}}" } diff --git a/public/locales/sp/translation.json b/public/locales/sp/translation.json index 1b7afe2365..2683940879 100644 --- a/public/locales/sp/translation.json +++ b/public/locales/sp/translation.json @@ -121,7 +121,8 @@ "spamsThe": "envía correo no deseado", "group": "grupo", "noNotifications": "No Notificaciones", - "close": "Cerca" + "close": "Cerca", + "Advertisement": "Publicidad" }, "orgList": { "title": "Organizaciones Talawa", @@ -159,7 +160,11 @@ "noOrgErrorDescription": "Por favor, crea una organización a través del panel de control", "noResultsFoundFor": "No se encontraron resultados para ", "OR": "O", - "sampleOrgSuccess": "Organización de ejemplo creada exitosamente" + "sampleOrgSuccess": "Organización de ejemplo creada exitosamente", + "manageFeatures": "Gestionar funciones", + "manageFeaturesInfo": "Información de gestión de funciones", + "goToStore": "Ir a la tienda", + "enableEverything": "Habilitar todo" }, "orgListCard": { "admins": "Administradores", @@ -227,7 +232,8 @@ "AlreadyJoined": "Ya eres miembro de esta organización.", "errorOccured": "Se produjo un error. Por favor, inténtalo de nuevo más tarde.", "removeUserFrom": "Eliminar Usuario de {{org}}", - "removeConfirmation": "¿Está seguro de que desea eliminar a '{{name}}' de la organización '{{org}}'?" + "removeConfirmation": "¿Está seguro de que desea eliminar a '{{name}}' de la organización '{{org}}'?", + "noOrgError": "Error sin organización" }, "communityProfile": { "title": "Perfil de la comunidad", @@ -292,7 +298,68 @@ "organization": "Organización", "create": "Crear", "cancel": "Cancelar", - "invalidDetailsMessage": "Ingrese detalles válidos." + "invalidDetailsMessage": "Ingrese detalles válidos.", + "addMembers": "Agregar miembros", + "searchFullName": "Ingrese el nombre completo", + "user": "Usuario", + "profile": "Perfil" + }, + "organizationTags": { + "title": "Etiquetas de Organización", + "createTag": "Crear una nueva etiqueta", + "manageTag": "Gestionar", + "editTag": "Editar", + "removeTag": "Eliminar", + "tagDetails": "Detalles de la Etiqueta", + "tagName": "Nombre", + "tagType": "Tipo", + "tagNamePlaceholder": "Escribe el nombre de la etiqueta", + "tagCreationSuccess": "Nueva etiqueta creada con éxito", + "tagUpdationSuccess": "Etiqueta actualizada con éxito", + "tagRemovalSuccess": "Etiqueta eliminada con éxito", + "noTagsFound": "No se encontraron etiquetas", + "removeUserTag": "Eliminar Etiqueta", + "removeUserTagMessage": "¿Desea eliminar esta etiqueta?", + "addChildTag": "Agregar una Sub Etiqueta" + }, + "manageTag": { + "title": "Detalles de la Etiqueta", + "addPeopleToTag": "Agregar Personas a la etiqueta", + "viewProfile": "Ver", + "noAssignedMembersFound": "Ningún miembro asignado", + "unassignUserTag": "Desasignar Etiqueta", + "unassignUserTagMessage": "¿Desea eliminar la etiqueta de este usuario?", + "successfullyUnassigned": "Etiqueta desasignada del usuario", + "addPeople": "Agregar Personas", + "add": "Agregar", + "subTags": "Subetiquetas", + "assignedToAll": "Etiqueta asignada a todos", + "successfullyAssignedToPeople": "Etiqueta asignada con éxito", + "errorOccurredWhileLoadingMembers": "Error al cargar los miembros", + "userName": "Nombre de usuario", + "actions": "Acciones", + "noOneSelected": "Nadie seleccionado", + "assignToTags": "Asignar a etiquetas", + "removeFromTags": "Eliminar de etiquetas", + "assign": "Asignar", + "remove": "Eliminar", + "successfullyAssignedToTags": "Asignado a etiquetas con éxito", + "successfullyRemovedFromTags": "Eliminado de etiquetas con éxito", + "errorOccurredWhileLoadingOrganizationUserTags": "Error al cargar las etiquetas de la organización", + "errorOccurredWhileLoadingSubTags": "Ocurrió un error al cargar las subetiquetas", + "removeUserTag": "Eliminar etiqueta", + "removeUserTagMessage": "¿Desea eliminar esta etiqueta? Esto eliminará todas las subetiquetas y todas las asociaciones.", + "tagDetails": "Detalles de la etiqueta", + "tagName": "Nombre", + "tagUpdationSuccess": "Etiqueta actualizada con éxito", + "tagRemovalSuccess": "Etiqueta eliminada con éxito", + "noTagSelected": "Ninguna etiqueta seleccionada", + "changeNameToEdit": "Cambia el nombre para hacer una actualización", + "selectTag": "Seleccionar etiqueta", + "collapse": "Colapsar", + "expand": "Expandir", + "tagNamePlaceholder": "Escribe el nombre de la etiqueta", + "allTags": "Todas las etiquetas" }, "userListCard": { "joined": "Unido", @@ -370,7 +437,6 @@ "active": "Activo", "clearFilters": "Borrar filtros", "close": "Cerrar", - "completed": "Completado", "completionDate": "Fecha de finalización", "createActionItem": "Crear ítem de acción", "deleteActionItem": "Eliminar ítem de acción", @@ -396,7 +462,14 @@ "successfulUpdation": "Ítem de acción actualizado con éxito", "successfulDeletion": "Ítem de acción eliminado con éxito", "title": "Ítems de acción", - "yes": "Sí" + "yes": "Sí", + "category": "Categoría", + "allotedHours": "Horas Asignadas", + "latestDueDate": "Fecha de Vencimiento Más Reciente", + "earliestDueDate": "Fecha de Vencimiento Más Temprana", + "updateActionItem": "Actualizar Elemento de Acción", + "noneUpdated": "Ninguno de los campos fue actualizado", + "updateStatusMsg": "¿Estás seguro de que deseas marcar este elemento de acción como pendiente?" }, "organizationAgendaCategory": { "agendaCategoryDetails": "Detalles de la categoría de la agenda", @@ -415,6 +488,40 @@ "deleteAgendaCategory": "Eliminar categoría de la agenda", "deleteAgendaCategoryMsg": "¿Desea eliminar esta categoría de la agenda?" }, + "agendaItems": { + "agendaItemDetails": "Detalles del punto del orden del día", + "updateAgendaItem": "Actualizar punto del orden del día", + "title": "Título", + "enterTitle": "Ingresar título", + "sequence": "Secuencia", + "description": "Descripción", + "enterDescription": "Ingresar descripción", + "category": "Categoría del orden del día", + "attachments": "Archivos adjuntos", + "attachmentLimit": "Agregar cualquier archivo de imagen o video hasta 10MB", + "fileSizeExceedsLimit": "El tamaño del archivo excede el límite de 10MB", + "urls": "URLs", + "url": "Agregar enlace a URL", + "enterUrl": "https://example.com", + "invalidUrl": "Ingrese una URL válida", + "link": "Enlace", + "createdBy": "Creado por", + "regular": "Regular", + "note": "Nota", + "duration": "Duración", + "enterDuration": "mm:ss", + "options": "Opciones", + "createAgendaItem": "Crear punto del orden del día", + "noAgendaItems": "No hay puntos del orden del día", + "selectAgendaItemCategory": "Seleccionar una categoría de punto del orden del día", + "update": "Actualizar", + "delete": "Eliminar", + "agendaItemCreated": "Punto del orden del día creado exitosamente", + "agendaItemUpdated": "Punto del orden del día actualizado exitosamente", + "agendaItemDeleted": "Punto del orden del día eliminado exitosamente", + "deleteAgendaItem": "Eliminar punto del orden del día", + "deleteAgendaItemMsg": "¿Desea eliminar este punto del orden del día?" + }, "eventListCard": { "location": "Lugar del evento", "deleteEvent": "Eliminar evento", @@ -456,65 +563,53 @@ "funds": { "title": "Fondos", "createFund": "Crear fondo", - "fundName": "Nombre del Fondo", - "fundId": "ID del Fondo", - "fundOptions": "Opciones", - "noFunds": "No se encontraron fondos", - "fundDetails": "Detalles del Fondo", + "fundName": "Nombre del fondo", + "fundId": "ID de referencia del fondo", "taxDeductible": "Deducible de impuestos", - "enterfundName": "Ingrese el nombre del fondo", - "enterfundId": "Ingrese el ID del fondo", - "default": "Fondo predeterminado", + "default": "Predeterminado", "archived": "Archivado", - "nonArchive": "No archivado", - "fundCreate": "Crear Fondo", - "fundUpdate": "Actualizar Fondo", - "fundDelete": "Eliminar Fondo", - "no": "No", - "yes": "Sí", - "manageFund": "Administrar fondo", - "searchFullName": "Buscar por nombre", - "filter": "Filtrar", + "fundCreate": "Crear fondo", + "fundUpdate": "Actualizar fondo", + "fundDelete": "Eliminar fondo", + "searchByName": "Buscar por nombre", "noFundsFound": "No se encontraron fondos", "createdBy": "Creado por", - "createdOn": "Creado el", + "createdOn": "Creado en", "status": "Estado", - "archiveFund": "Archivar Fondo", - "archiveFundMsg": "¿Desea archivar este fondo?", - "fundCreated": "Fondo creado exitosamente", - "fundUpdated": "Fondo actualizado exitosamente", - "fundDeleted": "Fondo eliminado exitosamente", - "fundArchived": "Fondo archivado exitosamente", - "fundUnarchived": "Fondo no archivado exitosamente", - "deleteFundMsg": "¿Desea eliminar este fondo?" + "fundCreated": "Fondo creado correctamente", + "fundUpdated": "Fondo actualizado correctamente", + "fundDeleted": "Fondo eliminado correctamente", + "deleteFundMsg": "¿Está seguro de que desea eliminar este fondo?", + "createdLatest": "Creado más reciente", + "createdEarliest": "Creado más temprano", + "viewCampaigns": "Ver campañas" }, "fundCampaign": { "title": "Campañas de recaudación de fondos", "campaignName": "Nombre de la campaña", - "startDate": "Fecha de inicio", - "endDate": "Fecha de finalización", - "campaignOptions": "Opciones de la campaña", - "fundingGoal": "Meta de financiamiento", + "campaignOptions": "Opciones", + "fundingGoal": "Meta de financiación", "addCampaign": "Agregar campaña", - "createdCampaign": "Campaña creada exitosamente", - "updatedCampaign": "Campaña actualizada exitosamente", - "deletedCampaign": "Campaña eliminada exitosamente", - "deleteCampaignMsg": "¿Desea eliminar esta campaña?", + "createdCampaign": "Campaña creada correctamente", + "updatedCampaign": "Campaña actualizada correctamente", + "deletedCampaign": "Campaña eliminada correctamente", + "deleteCampaignMsg": "¿Está seguro de que desea eliminar esta campaña?", "noCampaigns": "No se encontraron campañas", - "createCampaign": "Crear campaña de recaudación de fondos", - "updateCampaign": "Actualizar campaña de recaudación de fondos", - "manageCampaign": "Administrar campaña de recaudación de fondos", - "deleteCampaign": "Eliminar campaña de recaudación de fondos", - "no": "No", - "yes": "Sí", + "createCampaign": "Crear campaña", + "updateCampaign": "Actualizar campaña", + "deleteCampaign": "Eliminar campaña", "currency": "Moneda", "selectCurrency": "Seleccionar moneda", - "filter": "Filtrar", - "searchFullName": "Buscar por nombre" + "searchFullName": "Buscar por nombre", + "viewPledges": "Ver compromisos", + "noCampaignsFound": "No se encontraron campañas", + "latestEndDate": "Fecha de finalización más reciente", + "earliestEndDate": "Fecha de finalización más temprana", + "lowestGoal": "Meta más baja", + "highestGoal": "Meta más alta" }, "pledges": { "title": "Compromisos de Campaña de Financiamiento", - "volunteers": "Voluntarios", "startDate": "Fecha de Inicio", "endDate": "Fecha de Finalización", "pledgeAmount": "Monto del Compromiso", @@ -531,15 +626,17 @@ "amount": "Monto", "editPledge": "Editar Compromiso", "deletePledgeMsg": "¿Estás seguro de que quieres eliminar este compromiso?", - "no": "No", - "yes": "Sí", "noPledges": "No se encontraron compromisos", - "sort": "Ordenar", - "searchVolunteer": "Buscar por voluntario", + "searchPledger": "Buscar por compromisos", "highestAmount": "Cantidad más alta", "lowestAmount": "Cantidad más baja", "latestEndDate": "Fecha de finalización más reciente", - "earliestEndDate": "Fecha de finalización más cercana" + "earliestEndDate": "Fecha de finalización más cercana", + "campaigns": "Campañas", + "pledges": "Compromisos", + "endsOn": "Finaliza el", + "raisedAmount": "Monto recaudado", + "pledgedAmount": "Monto comprometido" }, "orgPost": { @@ -608,7 +705,8 @@ "postDeleted": "Publicación eliminada exitosamente.", "postUpdated": "Publicación actualizada exitosamente.", "tag": "Su navegador no admite la etiqueta de video", - "talawaApiUnavailable": "El servicio Talawa-API no está disponible. ¿Está en funcionamiento? Compruebe también su conectividad de red." + "talawaApiUnavailable": "El servicio Talawa-API no está disponible. ¿Está en funcionamiento? Compruebe también su conectividad de red.", + "pin": "Fijar" }, "blockUnblockUser": { "title": "Usuario de bloqueo/desbloqueo de Talawa", @@ -636,6 +734,7 @@ "dashboard": "Tablero", "registrants": "Inscritos", "eventActions": "Acciones del evento", + "eventAgendas": "Agendas de eventos", "eventStats": "Estadísticas del evento", "attendance": "Asistencia", "to": "A" @@ -687,19 +786,16 @@ "amount": "Monto" }, "orgSettings": { - "title": "Configuración Talawa", - "pageName": "Configuración", + "title": "Configuración", "general": "General", "actionItemCategories": "Categorías de elementos de acción", - "updateYourDetails": "Actualiza tus datos", - "updateYourPassword": "Actualice su contraseña", - "updateOrganization": "Actualizar Organización", - "seeRequest": "Ver Solicitud", - "settings": "Ajustes", + "updateOrganization": "Actualizar organización", + "seeRequest": "Ver solicitud", "noData": "Sin datos", - "otherSettings": "Otras Configuraciones", - "changeLanguage": "Cambiar Idioma", - "manageCustomFields": "Gestionar Campos Personalizados" + "otherSettings": "Otras configuraciones", + "changeLanguage": "Cambiar idioma", + "manageCustomFields": "Administrar campos personalizados", + "agendaItemCategories": "Categorías de elementos de agenda" }, "deleteOrg": { "deleteOrganization": "Eliminar organización", @@ -728,7 +824,9 @@ "newPassword": "Nueva contraseña", "confirmNewPassword": "Confirmar nueva contraseña", "saveChanges": "Guardar cambios", - "cancel": "Cancelar" + "cancel": "Cancelar", + "passCantBeEmpty": "La contraseña no puede estar vacía", + "passNoMatch": "La nueva contraseña y la confirmación no coinciden." }, "orgDelete": { "deleteOrg": "Eliminar organización" @@ -789,7 +887,9 @@ "addOnEntry": { "enable": "Activada", "install": "Instalar", - "uninstall": "Desinstalar" + "uninstall": "Desinstalar", + "uninstallMsg": "Mensaje de desinstalación", + "installMsg": "Mensaje de instalación" }, "memberDetail": { "title": "Detalles del usuario", @@ -832,7 +932,9 @@ "membershipRequests": "Solicitudes de membresía", "adminForEvents": "Administrador de eventos", "addedAsAdmin": "El usuario se agrega como administrador.", - "talawaApiUnavailable": "El servicio Talawa-API no está disponible. Compruebe amablemente su conexión de red y espere un momento." + "talawaApiUnavailable": "El servicio Talawa-API no está disponible. Compruebe amablemente su conexión de red y espere un momento.", + "deleteUser": "Eliminar usuario", + "userType": "Tipo de usuario" }, "userLogin": { "login": "Acceso", @@ -848,6 +950,10 @@ "invalidCredentials": "Las credenciales ingresadas son incorrectas. Ingrese credenciales válidas.", "talawaApiUnavailable": "El servicio Talawa-API no está disponible. Compruebe amablemente su conexión de red y espere un momento." }, + "people": { + "title": "Gente", + "searchUsers": "Buscar usuarios" + }, "userRegister": { "register": "Registro", "firstName": "Nombre de pila", @@ -888,7 +994,9 @@ "selectOrganization": "Seleccionar organización", "filter": "Filtrar", "organizations": "Organizaciones", - "searchByName": "Buscar por nombre" + "searchByName": "Buscar por nombre", + "searchUsers": "Buscar usuarios", + "searchOrganizations": "Buscar Organizaciones" }, "userSidebarOrg": { "yourOrganizations": "Tus Organizaciones", @@ -901,7 +1009,8 @@ "requests": "Solicitudes", "communityProfile": "Perfil de la comunidad", "logout": "Cerrar sesión", - "settings": "Ajustes" + "settings": "Ajustes", + "chat": "Chat" }, "organizationSidebar": { "viewAll": "Ver todo", @@ -912,17 +1021,28 @@ }, "postCard": { "likes": "Gustos", - "comments": "Comentarios" + "comments": "Comentarios", + "viewPost": "Ver publicación", + "editPost": "Editar publicación", + "postedOn": "Publicado el {{date}}" }, "home": { - "feed": "Alimentar", - "pinnedPosts": "Ver publicaciones fijadas", - "somethingOnYourMind": "¿Algo en tu mente?", - "addPost": "Agregar publicación", + "posts": "Publicaciones", + "post": "Publicación", + "title": "Publicaciones", + "textArea": "¿Tienes algo en mente?", + "feed": "Feed", + "loading": "Cargando", + "pinnedPosts": "Publicaciones fijadas", + "yourFeed": "Tu feed", + "nothingToShowHere": "No hay nada que mostrar aquí", + "somethingOnYourMind": "¿Tienes algo en mente?", + "addPost": "Añadir publicación", "startPost": "Comenzar una publicación", "media": "Medios", "event": "Evento", - "article": "Artículo" + "article": "Artículo", + "postNowVisibleInFeed": "Publicar ahora visible en el feed" }, "settings": { "settings": "Ajustes", @@ -965,7 +1085,7 @@ "divorced": "Divorciado", "widowed": "Viudo", "engaged": "Comprometido", - "seperated": "Separado", + "separated": "Separado", "grade1": "1er Grado", "grade2": "2do Grado", "grade3": "3er Grado", @@ -989,6 +1109,7 @@ "joined": "Unido" }, "donate": { + "title": "Donaciones", "donations": "Donaciones", "searchDonations": "Buscar donaciones", "donateForThe": "Donar para el", @@ -997,9 +1118,13 @@ "yourPreviousDonations": "Tus donaciones anteriores", "donate": "Donar", "nothingToShow": "Nada que mostrar aquí.", - "success": "Donación exitosa" + "success": "Donación exitosa", + "invalidAmount": "Ingrese un valor numérico para el monto de la donación.", + "donationAmountDescription": "Ingrese el valor numérico del monto de la donación.", + "donationOutOfRange": "El monto de la donación debe estar entre {{min}} y {{max}}." }, "userEvents": { + "title": "Eventos", "nothingToShow": "No hay nada que mostrar aquí.", "search": "Buscar", "createEvent": "Crear evento", @@ -1052,13 +1177,26 @@ "view": "Ver", "edit": "Editar", "editAdvertisement": "Editar Anuncio", + "advertisementDeleted": "Anuncio eliminado con éxito.", + "endDateGreaterOrEqual": "La fecha de finalización debe ser mayor o igual a la fecha de inicio", + "advertisementCreated": "Anuncio creado con éxito.", "saveChanges": "Guardar Cambios", - "endOfResults": "Fin de los resultados" + "endOfResults": "Fin de los resultados", + "Rname": "Nombre", + "Rtype": "Tipo", + "RstartDate": "Fecha de inicio", + "RendDate": "Fecha de finalización", + "RClose": "Cerrar", + "addNew": "Agregar nuevo", + "EXname": "Nombre", + "EXlink": "Enlace", + "createAdvertisement": "Crear publicidad" }, "userChat": { "chat": "Charlar", "search": "Buscar", - "contacts": "Contactos" + "contacts": "Contactos", + "messages": "Mensajes" }, "userChatRoom": { "selectContact": "Seleccione un contacto para iniciar una conversación", @@ -1086,13 +1224,18 @@ "disableButton": "Inhabilitar", "updateActionItemCategory": "Actualizar", "actionItemCategoryName": "Nombre", - "actionItemCategoryDetails": "Detalles de la categoría de elemento de acción", + "categoryDetails": "Detalles de la categoría", "enterName": "Introduzca el nombre", "successfulCreation": "Categoría de elemento de acción creada correctamente", "successfulUpdation": "Categoría de elemento de acción actualizada correctamente", "sameNameConflict": "Cambie el nombre para realizar una actualización", "categoryEnabled": "Categoría de elemento de acción habilitada", - "categoryDisabled": "Categoría de elemento de acción deshabilitada" + "categoryDisabled": "Categoría de elemento de acción deshabilitada", + "noActionItemCategories": "No hay categorías de elementos de acción", + "status": "Estado", + "categoryDeleted": "Categoría de elemento de acción eliminada con éxito", + "deleteCategory": "Eliminar categoría", + "deleteCategoryMsg": "¿Está seguro de que desea eliminar esta categoría de elemento de acción?" }, "organizationVenues": { "title": "Lugares", @@ -1145,6 +1288,7 @@ "invalidDetailsMessage": "Por favor proporcione todos los detalles requeridos.", "passwordNotMatch": "Las contraseñas no coinciden.", "user": "Usuario", + "profile": "Perfil", "addMember": "Agregar miembro" }, "eventActionItems": { @@ -1153,8 +1297,8 @@ "actionItemCategory": "Categoría de elemento de acción", "selectActionItemCategory": "Seleccione una categoría de elemento de acción", "selectAssignee": "Seleccione un asignado", - "preCompletionNotes": "Notas previas a la finalización", - "postCompletionNotes": "Publicar notas de finalización", + "preCompletionNotes": "Notas", + "postCompletionNotes": "Notas finales", "actionItemDetails": "Detalles del elemento de acción", "dueDate": "Fecha de vencimiento", "completionDate": "Fecha de finalización", @@ -1167,6 +1311,43 @@ "successfulCreation": "Elemento de acción creado exitosamente", "successfulUpdation": "Elemento de acción actualizado correctamente", "notes": "Notas", + "assignee": "Cesionario", + "assigner": "Asignador", + "assignmentDate": "Fecha de asignación", + "status": "Estado", + "actionItemActive": "Activo", + "actionItemStatus": "Estado del elemento de acción", + "actionItemCompleted": "Elemento de acción completado", + "markCompletion": "Marcar finalización", "save": "Guardar" + }, + "checkIn": { + "errorCheckingIn": "Error al registrarse", + "checkedInSuccessfully": "Registrado con éxito" + }, + "eventRegistrantsModal": { + "errorAddingAttendee": "Error al agregar asistente", + "errorRemovingAttendee": "Error al eliminar asistente" + }, + "userCampaigns": { + "title": "Campañas de recaudación de fondos", + "searchByName": "Buscar por nombre...", + "searchBy": "Buscar por", + "pledgers": "Contribuyentes", + "campaigns": "Campañas", + "myPledges": "Mis Promesas", + "lowestAmount": "Monto más bajo", + "highestAmount": "Monto más alto", + "lowestGoal": "Meta más baja", + "highestGoal": "Meta más alta", + "latestEndDate": "Fecha de finalización más tardía", + "earliestEndDate": "Fecha de finalización más temprana", + "addPledge": "Añadir Promesa", + "viewPledges": "Ver Promesas", + "noPledges": "No se encontraron promesas", + "noCampaigns": "No se encontraron campañas" + }, + "userPledges": { + "title": "Mis Promesas" } } diff --git a/public/locales/zh/common.json b/public/locales/zh/common.json index 3e3da4db19..7d47336692 100644 --- a/public/locales/zh/common.json +++ b/public/locales/zh/common.json @@ -75,6 +75,23 @@ "profile": "轮廓", "noFiltersApplied": "未应用筛选器", "manage": "管理", - "searchResultsFor": "搜索结果:{{text}}", - "none": "没有" + "searchResultsFor": "搜索结果", + "none": "没有", + "sort": "种类", + "Donate": "捐赠", + "addedSuccessfully": "{{item}} 添加成功", + "updatedSuccessfully": "{{item}} 更新成功", + "removedSuccessfully": "{{item}} 删除成功", + "successfullyUpdated": "更新成功", + "sessionWarning": "由于不活动,您的会话即将过期。请与页面互动以延长您的会话。", + "sessionLogOut": "由于不活动,您的会话已过期。请重新登录以继续。", + "all": "全部", + "active": "活跃", + "disabled": "禁用", + "pending": "待处理", + "completed": "已完成", + "late": "迟到", + "createdLatest": "最近创建", + "createdEarliest": "最早创建", + "searchBy": "搜索依据 {{item}}" } diff --git a/public/locales/zh/errors.json b/public/locales/zh/errors.json index 7ddfe06ab4..c872f367a5 100644 --- a/public/locales/zh/errors.json +++ b/public/locales/zh/errors.json @@ -5,5 +5,7 @@ "notAuthorised": "对不起!", "errorSendingMail": "发送邮件时出错", "emailNotRegistered": "邮箱未注册", - "notFoundMsg": "哎呀!" + "notFoundMsg": "哎呀!", + "errorOccurredCouldntCreate": "发生错误。 无法创建{{entity}}", + "errorLoading": "加载{{entity}}数据时出错" } diff --git a/public/locales/zh/translation.json b/public/locales/zh/translation.json index dc7d7e9d6d..c0a958f4e0 100644 --- a/public/locales/zh/translation.json +++ b/public/locales/zh/translation.json @@ -22,7 +22,25 @@ "numeric_value_check": "至少设定一个数值", "special_char_check": "至少一个特殊字符", "selectOrg": "选择一个组织", - "afterRegister": "注册成功。" + "afterRegister": "注册成功。", + "talawa_portal": "塔拉瓦门户", + "login": "登录", + "register": "注册", + "firstName": "名字", + "lastName": "姓氏", + "email": "电子邮件", + "password": "密码", + "confirmPassword": "确认密码", + "forgotPassword": "忘记密码", + "enterEmail": "输入电子邮件", + "enterPassword": "输入密码", + "talawaApiUnavailable": "塔拉瓦 API 不可用", + "notAuthorised": "未授权", + "notFound": "未找到", + "OR": "或", + "admin": "管理员", + "user": "用户", + "loading": "加载中" }, "userLoginPage": { "title": "塔拉瓦管理员", @@ -38,7 +56,23 @@ "successfullyRegistered": "注册成功。", "userLogin": "用户登录", "afterRegister": "注册成功。", - "selectOrg": "选择一个组织" + "selectOrg": "选择一个组织", + "talawa_portal": "塔拉瓦门户", + "login": "登录", + "register": "注册", + "firstName": "名字", + "lastName": "姓氏", + "email": "电子邮件", + "password": "密码", + "confirmPassword": "确认密码", + "forgotPassword": "忘记密码", + "enterEmail": "输入电子邮件", + "enterPassword": "输入密码", + "talawaApiUnavailable": "塔拉瓦 API 不可用", + "notAuthorised": "未授权", + "notFound": "未找到", + "OR": "或", + "loading": "加载中" }, "latestEvents": { "eventCardTitle": "即将举行的活动", @@ -51,12 +85,19 @@ "noPostsCreated": "没有创建帖子" }, "listNavbar": { - "roles": "角色" + "roles": "角色", + "talawa_portal": "塔拉瓦门户", + "requests": "请求", + "logout": "退出登录" }, "leftDrawer": { "my organizations": "我的组织", "requests": "会员申请", - "communityProfile": "社区简介" + "communityProfile": "社区简介", + "talawaAdminPortal": "塔拉瓦管理员门户", + "menu": "菜单", + "users": "用户", + "logout": "退出登录" }, "leftDrawerOrg": { "Dashboard": "仪表板", @@ -75,7 +116,13 @@ "notifications": "通知", "spamsThe": "垃圾邮件", "group": "团体", - "noNotifications": "无通知" + "noNotifications": "无通知", + "talawaAdminPortal": "塔拉瓦管理员门户", + "menu": "菜单", + "talawa_portal": "塔拉瓦门户", + "settings": "设置", + "logout": "退出登录", + "close": "关闭" }, "orgList": { "title": "塔拉瓦组织", @@ -105,11 +152,25 @@ "manageFeaturesInfo": "创建成功!", "goToStore": "前往插件商店", "enableEverything": "启用一切", - "sampleOrgSuccess": "样本组织已成功创建" + "sampleOrgSuccess": "样本组织已成功创建", + "name": "名称", + "email": "电子邮件", + "searchByName": "按名称搜索", + "description": "描述", + "location": "位置", + "address": "地址", + "displayImage": "显示图像", + "filter": "筛选", + "cancel": "取消", + "endOfResults": "结果结束", + "noResultsFoundFor": "未找到结果", + "OR": "或" }, "orgListCard": { "manage": "管理", - "sampleOrganization": "组织样本" + "sampleOrganization": "组织样本", + "admins": "管理员", + "members": "成员" }, "paginationList": { "rowsPerPage": "每页行数", @@ -126,7 +187,11 @@ "acceptedSuccessfully": "请求已成功接受", "rejectedSuccessfully": "请求被成功拒绝", "noOrgErrorTitle": "未找到组织", - "noOrgErrorDescription": "请通过仪表板创建组织" + "noOrgErrorDescription": "请通过仪表板创建组织", + "name": "名称", + "email": "电子邮件", + "endOfResults": "结果结束", + "noResultsFoundFor": "未找到结果" }, "users": { "title": "塔拉瓦角色", @@ -150,7 +215,25 @@ "visit": "访问", "withdraw": "拉幅", "removeUserFrom": "从{{org}}中删除用户", - "removeConfirmation": "您确定要将'{{name}}'从组织'{{org}}'中删除吗?" + "removeConfirmation": "您确定要将'{{name}}'从组织'{{org}}'中删除吗?", + "searchByName": "按名称搜索", + "users": "用户", + "name": "名称", + "email": "电子邮件", + "endOfResults": "结果结束", + "admin": "管理员", + "superAdmin": "超级管理员", + "user": "用户", + "filter": "筛选", + "noResultsFoundFor": "未找到结果", + "talawaApiUnavailable": "塔拉瓦 API 不可用", + "cancel": "取消", + "admins": "管理员", + "members": "成员", + "orgJoined": "已加入组织", + "MembershipRequestSent": "会员请求已发送", + "AlreadyJoined": "已加入", + "errorOccured": "发生错误" }, "communityProfile": { "title": "社区简介", @@ -178,7 +261,12 @@ "latestPosts": "最新帖子", "noPostsPresent": "没有帖子", "membershipRequests": "会员请求", - "noMembershipRequests": "没有会员请求" + "noMembershipRequests": "没有会员请求", + "location": "位置", + "members": "成员", + "admins": "管理员", + "requests": "请求", + "talawaApiUnavailable": "塔拉瓦 API 不可用" }, "organizationPeople": { "title": "塔拉瓦会员", @@ -198,23 +286,106 @@ "enterLastName": "输入您的姓氏", "enterConfirmPassword": "输入您的密码进行确认", "organization": "组织", - "invalidDetailsMessage": "请输入有效的详细信息。" + "invalidDetailsMessage": "请输入有效的详细信息。", + "members": "成员", + "admins": "管理员", + "users": "用户", + "searchFirstName": "按名字搜索", + "searchLastName": "按姓氏搜索", + "firstName": "名字", + "lastName": "姓氏", + "emailAddress": "电子邮件地址", + "enterEmail": "输入你的电子邮件地址", + "password": "密码", + "enterPassword": "输入你的密码", + "confirmPassword": "确认密码", + "cancel": "取消", + "create": "创建", + "user": "用户", + "profile": "个人资料" + }, + "organizationTags": { + "title": "组织标签", + "createTag": "创建新标签", + "manageTag": "管理", + "editTag": "编辑", + "removeTag": "删除", + "tagDetails": "标签详情", + "tagName": "名称", + "tagType": "类型", + "tagNamePlaceholder": "输入标签名称", + "tagCreationSuccess": "新标签创建成功", + "tagUpdationSuccess": "标签更新成功", + "tagRemovalSuccess": "标签删除成功", + "noTagsFound": "未找到标签", + "removeUserTag": "删除标签", + "removeUserTagMessage": "您确定要删除此标签吗?", + "addChildTag": "添加子标签" + }, + "manageTag": { + "title": "标签详情", + "addPeopleToTag": "将人员添加到标签", + "viewProfile": "查看", + "noAssignedMembersFound": "没有分配成员", + "unassignUserTag": "取消分配标签", + "unassignUserTagMessage": "您想从此用户中删除标签吗?", + "successfullyUnassigned": "标签已从用户中取消分配", + "addPeople": "添加人员", + "add": "添加", + "subTags": "子标签", + "assignedToAll": "标签分配给所有人", + "successfullyAssignedToPeople": "标签分配成功", + "errorOccurredWhileLoadingMembers": "加载成员时出错", + "userName": "用户名", + "actions": "操作", + "noOneSelected": "未选择任何人", + "assignToTags": "分配到标签", + "removeFromTags": "从标签中移除", + "assign": "分配", + "remove": "移除", + "successfullyAssignedToTags": "成功分配到标签", + "successfullyRemovedFromTags": "成功从标签中移除", + "errorOccurredWhileLoadingOrganizationUserTags": "加载组织标签时出错", + "errorOccurredWhileLoadingSubTags": "加载子标签时发生错误", + "removeUserTag": "删除标签", + "removeUserTagMessage": "您要删除此标签吗?这将删除所有子标签和所有关联。", + "tagDetails": "标签详情", + "tagName": "名称", + "tagUpdationSuccess": "标签更新成功", + "tagRemovalSuccess": "标签删除成功", + "noTagSelected": "未选择标签", + "changeNameToEdit": "更改名称以进行更新", + "selectTag": "选择标签", + "collapse": "收起", + "expand": "展开", + "tagNamePlaceholder": "输入标签名称", + "allTags": "所有标签" }, "userListCard": { "addAdmin": "添加管理员", - "addedAsAdmin": "用户被添加为管理员。" + "addedAsAdmin": "用户被添加为管理员。", + "joined": "已加入", + "talawaApiUnavailable": "塔拉瓦 API 不可用" }, "orgAdminListCard": { "remove": "消除", "removeAdmin": "删除管理员", "removeAdminMsg": "您想删除该管理员吗?", - "adminRemoved": "管理员被删除。" + "adminRemoved": "管理员被删除。", + "joined": "已加入", + "no": "否", + "yes": "是", + "talawaApiUnavailable": "塔拉瓦 API 不可用" }, "orgPeopleListCard": { "remove": "消除", "removeMember": "删除会员", "removeMemberMsg": "您想删除该成员吗?", - "memberRemoved": "该会员已被删除" + "memberRemoved": "该会员已被删除", + "joined": "已加入", + "no": "否", + "yes": "是", + "talawaApiUnavailable": "塔拉瓦 API 不可用" }, "organizationEvents": { "title": "活动", @@ -245,7 +416,14 @@ "never": "绝不", "on": "在", "after": "后", - "occurences": "事件" + "occurences": "事件", + "events": "活动", + "description": "描述", + "location": "位置", + "startDate": "开始日期", + "endDate": "结束日期", + "talawaApiUnavailable": "塔拉瓦 API 不可用", + "done": "完成" }, "organizationActionItems": { "actionItemCategory": "行动项目类别", @@ -256,7 +434,6 @@ "assignmentDate": "分配日期", "active": "积极的", "clearFilters": "清除过滤器", - "completed": "完全的", "completionDate": "完成日期", "createActionItem": "创建操作项", "deleteActionItem": "删除操作项", @@ -267,6 +444,7 @@ "editActionItem": "编辑操作项", "isCompleted": "完全的", "latest": "最新的", + "makeActive": "积极的", "noActionItems": "无行动项目", "options": "选项", "preCompletionNotes": "预完成注释", @@ -280,7 +458,18 @@ "successfulCreation": "操作项创建成功", "successfulUpdation": "操作项已成功更新", "successfulDeletion": "操作项已成功删除", - "title": "行动项目" + "title": "行动项目", + "category": "类别", + "allotedHours": "分配的小时", + "latestDueDate": "最晚到期日", + "earliestDueDate": "最早到期日", + "updateActionItem": "更新操作项", + "noneUpdated": "没有更新任何字段", + "updateStatusMsg": "您确定要将此操作项标记为待处理吗?", + "close": "关闭", + "eventActionItems": "活动行动项目", + "no": "否", + "yes": "是" }, "organizationAgendaCategory": { "agendaCategoryDetails": "议程类别详情", @@ -299,6 +488,40 @@ "deleteAgendaCategory": "删除议程类别", "deleteAgendaCategoryMsg": "是否要删除此议程类别?" }, + "agendaItems": { + "agendaItemDetails": "议程项目详细信息", + "updateAgendaItem": "更新议程项目", + "title": "标题", + "enterTitle": "输入标题", + "sequence": "顺序", + "description": "描述", + "enterDescription": "输入描述", + "category": "议程类别", + "attachments": "附件", + "attachmentLimit": "添加任何图像文件或视频文件,最大 10MB", + "fileSizeExceedsLimit": "文件大小超过 10MB 的限制", + "urls": "网址", + "url": "添加链接到网址", + "enterUrl": "https://example.com", + "invalidUrl": "请输入有效的网址", + "link": "链接", + "createdBy": "创建人", + "regular": "常规", + "note": "注意", + "duration": "持续时间", + "enterDuration": "分:秒", + "options": "选项", + "createAgendaItem": "创建议程项目", + "noAgendaItems": "没有议程项目", + "selectAgendaItemCategory": "选择议程项目类别", + "update": "更新", + "delete": "删除", + "agendaItemCreated": "议程项目已成功创建", + "agendaItemUpdated": "议程项目已成功更新", + "agendaItemDeleted": "议程项目已成功删除", + "deleteAgendaItem": "删除议程项目", + "deleteAgendaItemMsg": "您要删除此议程项目吗?" + }, "eventListCard": { "deleteEvent": "删除事件", "deleteEventMsg": "您想删除此事件吗?", @@ -325,62 +548,68 @@ "never": "绝不", "on": "在", "after": "后", - "occurences": "事件" + "occurences": "事件", + "location": "位置", + "no": "否", + "yes": "是", + "description": "描述", + "startDate": "开始日期", + "endDate": "结束日期", + "registerEvent": "注册活动", + "close": "关闭", + "talawaApiUnavailable": "塔拉瓦 API 不可用", + "done": "完成" }, "funds": { - "title": "资金", + "title": "基金", "createFund": "创建基金", "fundName": "基金名称", - "fundId": "基金编号", - "fundOptions": "奥皮通斯", - "noFunds": "未找到资金", - "fundDetails": "基金详情", - "taxDeductible": "免税额", - "enterfundName": "输入基金名称", - "enterfundId": "输入基金ID", - "default": "违约基金", + "fundId": "基金(参考)ID", + "taxDeductible": "税前扣除", + "default": "默认", "archived": "已归档", - "nonArchive": "非存档", "fundCreate": "创建基金", "fundUpdate": "更新基金", "fundDelete": "删除基金", - "manageFund": "管理基金", - "searchFullName": "按名称搜索", - "noFundsFound": "未找到资金", - "createdBy": "由...制作", + "searchByName": "按名称搜索", + "noFundsFound": "未找到基金", + "createdBy": "由...创建", "createdOn": "创建于", - "status": "地位", - "archiveFund": "档案基金", - "archiveFundMsg": "存档后,该基金将从基金列表中删除。此操作可以撤消", + "status": "状态", "fundCreated": "基金创建成功", "fundUpdated": "基金更新成功", - "fundDeleted": "资金删除成功", - "fundArchived": "资金归档成功", - "fundUnarchived": "基金已成功解档", - "deleteFundMsg": "您想删除该基金吗?" + "fundDeleted": "基金删除成功", + "deleteFundMsg": "您确定要删除此基金吗?", + "createdLatest": "最近创建", + "createdEarliest": "最早创建", + "viewCampaigns": "查看活动" }, "fundCampaign": { - "title": "筹款活动", + "title": "募捐活动", "campaignName": "活动名称", "campaignOptions": "选项", - "fundingGoal": "资助目标", + "fundingGoal": "资金目标", "addCampaign": "添加活动", "createdCampaign": "活动创建成功", "updatedCampaign": "活动更新成功", - "deletedCampaign": "营销活动删除成功", - "deleteCampaignMsg": "您确定要删除此广告活动吗?", + "deletedCampaign": "活动删除成功", + "deleteCampaignMsg": "您确定要删除此活动吗?", "noCampaigns": "未找到活动", - "createCampaign": "创建基金活动", - "updateCampaign": "更新基金活动", - "manageCampaign": "管理基金活动", - "deleteCampaign": "删除基金活动", + "createCampaign": "创建活动", + "updateCampaign": "更新活动", + "deleteCampaign": "删除活动", "currency": "货币", "selectCurrency": "选择货币", - "searchFullName": "按名称搜索" + "searchFullName": "按名称搜索", + "viewPledges": "查看承诺", + "noCampaignsFound": "未找到活动", + "latestEndDate": "最新结束日期", + "earliestEndDate": "最早结束日期", + "lowestGoal": "最低目标", + "highestGoal": "最高目标" }, "pledges": { "title": "基金活动承诺", - "volunteers": "志愿者", "pledgeAmount": "质押金额", "pledgeOptions": "选项", "pledgeCreated": "质押创建成功", @@ -396,12 +625,18 @@ "editPledge": "编辑承诺", "deletePledgeMsg": "您确定要删除此承诺吗?", "noPledges": "未找到承诺", - "sort": "排序", - "searchVolunteer": "按志愿者搜索", + "searchPledger": "按承诺搜索", "highestAmount": "最高金额", "lowestAmount": "最低金额", "latestEndDate": "最新结束日期", - "earliestEndDate": "最早结束日期" + "earliestEndDate": "最早结束日期", + "campaigns": "活动", + "pledges": "承诺", + "endsOn": "结束于", + "raisedAmount": "募集金額", + "pledgedAmount": "承诺金額", + "startDate": "开始日期", + "endDate": "结束日期" }, "orgPost": { "title": "帖子", @@ -429,7 +664,8 @@ "postCreatedSuccess": "恭喜!", "pinPost": "针柱", "Next": "下一页", - "Previous": "上一页" + "Previous": "上一页", + "cancel": "取消" }, "postNotFound": { "post": "邮政", @@ -444,7 +680,8 @@ "user not found!": "未找到用户!", "member not found!": "未找到会员!", "admin not found!": "找不到管理员!", - "roles not found!": "未找到角色!" + "roles not found!": "未找到角色!", + "user": "用户" }, "orgPostCard": { "author": "作者", @@ -463,7 +700,12 @@ "postDeleted": "帖子删除成功。", "postUpdated": "帖子更新成功。", "tag": " 您的浏览器不支持video标签", - "pin": "针柱" + "pin": "针柱", + "edit": "编辑", + "no": "否", + "yes": "是", + "close": "关闭", + "talawaApiUnavailable": "塔拉瓦 API 不可用" }, "blockUnblockUser": { "title": "阻止/取消阻止用户", @@ -479,13 +721,19 @@ "blockedUsers": "被阻止的用户", "searchByFirstName": "按名字搜索", "searchByLastName": "按姓氏搜索", - "noSpammerFound": "未发现垃圾邮件发送者" + "noSpammerFound": "未发现垃圾邮件发送者", + "searchByName": "按名称搜索", + "name": "名称", + "email": "电子邮件", + "talawaApiUnavailable": "塔拉瓦 API 不可用", + "noResultsFoundFor": "未找到结果" }, "eventManagement": { "title": "事件管理", "dashboard": "仪表板", "registrants": "注册者", "eventActions": "事件动作", + "eventAgendas": "活动议程", "eventStats": "事件统计", "to": "到" }, @@ -503,7 +751,10 @@ "errorSendingMail": "发送邮件时出错。", "passwordMismatches": "密码和确认密码不匹配。", "passwordChanges": "密码修改成功。", - "OTPsent": "OTP 已发送至您的注册邮箱。" + "OTPsent": "OTP 已发送至您的注册邮箱。", + "forgotPassword": "忘记密码", + "password": "密码", + "talawaApiUnavailable": "塔拉瓦 API 不可用" }, "pageNotFound": { "404": "404", @@ -541,7 +792,8 @@ "noData": "没有数据", "otherSettings": "其他设置", "changeLanguage": "改变语言", - "manageCustomFields": "管理自定义字段" + "manageCustomFields": "管理自定义字段", + "agendaItemCategories": "议程项目类别" }, "deleteOrg": { "deleteOrganization": "删除组织", @@ -549,16 +801,30 @@ "deleteMsg": "您想删除该组织吗?", "confirmDelete": "确认删除", "longDelOrgMsg": "通过单击“删除组织”按钮,该组织及其事件、标签和所有相关数据将被永久删除。", - "successfullyDeletedSampleOrganization": "已成功删除样本组织" + "successfullyDeletedSampleOrganization": "已成功删除样本组织", + "cancel": "取消" }, "userUpdate": { "appLanguageCode": "默认语言", - "userType": "用户类型" + "userType": "用户类型", + "firstName": "名字", + "lastName": "姓氏", + "email": "电子邮件", + "password": "密码", + "admin": "管理员", + "superAdmin": "超级管理员", + "displayImage": "显示图像", + "saveChanges": "保存更改", + "cancel": "取消" }, "userPasswordUpdate": { "previousPassword": "旧密码", "newPassword": "新密码", - "confirmNewPassword": "确认新密码" + "confirmNewPassword": "确认新密码", + "passCantBeEmpty": "密码不能为空", + "passNoMatch": "新密码和确认密码不匹配。", + "saveChanges": "保存更改", + "cancel": "取消" }, "orgDelete": { "deleteOrg": "删除组织" @@ -566,7 +832,9 @@ "membershipRequest": { "accept": "接受", "reject": "拒绝", - "memberAdded": "它被接受" + "memberAdded": "它被接受", + "joined": "已加入", + "talawaApiUnavailable": "塔拉瓦 API 不可用" }, "orgUpdate": { "city": "城市", @@ -580,7 +848,15 @@ "userRegistrationRequired": "需要用户注册", "isVisibleInSearch": "在搜索中可见", "enterNameOrganization": "输入组织名称", - "successfulUpdated": "组织更新成功" + "successfulUpdated": "组织更新成功", + "name": "名称", + "description": "描述", + "location": "位置", + "address": "地址", + "displayImage": "显示图像", + "saveChanges": "保存更改", + "cancel": "取消", + "talawaApiUnavailable": "塔拉瓦 API 不可用" }, "addOnRegister": { "addNew": "添新", @@ -590,7 +866,9 @@ "pluginDesc": "插件说明", "pName": "例如:捐款", "cName": "例如:约翰·多伊", - "pDesc": "该插件启用 UI" + "pDesc": "该插件启用 UI", + "close": "关闭", + "register": "注册" }, "addOnStore": { "title": "添加商店", @@ -601,7 +879,8 @@ "pHeading": "插件", "install": "已安装", "available": "可用的", - "pMessage": "插件不存在" + "pMessage": "插件不存在", + "filter": "筛选" }, "addOnEntry": { "enable": "启用", @@ -646,14 +925,32 @@ "membershipRequests": "会员请求", "adminForEvents": "活动管理员", "addedAsAdmin": "用户被添加为管理员。", - "userType": "用户类型" + "userType": "用户类型", + "email": "电子邮件", + "displayImage": "显示图像", + "address": "地址", + "delete": "删除", + "saveChanges": "保存更改", + "joined": "已加入", + "talawaApiUnavailable": "塔拉瓦 API 不可用" }, "userLogin": { "login": "登录", "loginIntoYourAccount": "登录您的帐户", "invalidDetailsMessage": "请输入有效的电子邮件和密码。", "notAuthorised": "对不起!", - "invalidCredentials": "输入的凭据不正确。" + "invalidCredentials": "输入的凭据不正确。", + "forgotPassword": "忘记密码", + "emailAddress": "电子邮件地址", + "enterEmail": "输入电子邮件", + "password": "密码", + "enterPassword": "输入密码", + "register": "注册", + "talawaApiUnavailable": "塔拉瓦 API 不可用" + }, + "people": { + "title": "人们", + "searchUsers": "搜索用户" }, "userRegister": { "enterFirstName": "输入您的名字", @@ -663,7 +960,16 @@ "login": "登录", "afterRegister": "注册成功。", "passwordNotMatch": "密码不匹配。", - "invalidDetailsMessage": "请输入有效的详细信息。" + "invalidDetailsMessage": "请输入有效的详细信息。", + "register": "注册", + "firstName": "名字", + "lastName": "姓氏", + "emailAddress": "电子邮件地址", + "enterEmail": "输入电子邮件", + "password": "密码", + "enterPassword": "输入密码", + "confirmPassword": "确认密码", + "talawaApiUnavailable": "塔拉瓦 API 不可用" }, "userNavbar": { "talawa": "塔拉瓦", @@ -672,7 +978,10 @@ "events": "活动", "chat": "聊天", "donate": "捐", - "language": "语言" + "language": "语言", + "settings": "设置", + "logout": "退出登录", + "close": "关闭" }, "userOrganizations": { "allOrganizations": "所有组织", @@ -681,7 +990,11 @@ "selectOrganization": "选择一个组织", "searchUsers": "搜索用户", "nothingToShow": "这里没有什么可显示的。", - "organizations": "组织机构" + "organizations": "组织机构", + "search": "搜索", + "filter": "筛选", + "searchByName": "按名称搜索", + "searchOrganizations": "搜索组织" }, "userSidebarOrg": { "yourOrganizations": "您的组织", @@ -689,22 +1002,32 @@ "viewAll": "查看全部", "talawaUserPortal": "塔拉瓦用户门户", "my organizations": "我的组织", - "communityProfile": "社区简介" + "communityProfile": "社区简介", + "users": "用户", + "requests": "请求", + "logout": "登出", + "settings": "设置", + "chat": "聊天", + "menu": "菜单" }, "organizationSidebar": { "viewAll": "查看全部", "events": "活动", "noEvents": "没有可显示的活动", - "noMembers": "没有可显示的会员" + "noMembers": "没有可显示的会员", + "members": "成员" }, "postCard": { "likes": "喜欢", - "comments": "评论" + "comments": "评论", + "viewPost": "查看帖子", + "editPost": "编辑帖子", + "postedOn": "发布于 {{date}}" }, "home": { + "title": "帖子", "posts": "帖子", "post": "邮政", - "title": "标题", "textArea": "你有什么心事吗?", "feed": "喂养", "loading": "加载中", @@ -716,7 +1039,8 @@ "startPost": "开始发帖", "media": "媒体", "event": "事件", - "article": "文章" + "article": "文章", + "postNowVisibleInFeed": "帖子现在在动态中可见" }, "settings": { "noeventsAttended": "未参加任何活动", @@ -752,7 +1076,7 @@ "widowed": "寡", "divorced": "离婚", "engaged": "已订婚的", - "seperated": "分离的", + "separated": "分离的", "grade1": "1级", "grade2": "二年级", "grade3": "三年级", @@ -772,9 +1096,18 @@ "fullTime": "全职", "partTime": "兼职", "selectCountry": "选择一个国家", - "enterState": "输入城市或州" + "enterState": "输入城市或州", + "settings": "设置", + "firstName": "名字", + "lastName": "姓氏", + "emailAddress": "电子邮件地址", + "displayImage": "显示图像", + "address": "地址", + "saveChanges": "保存更改", + "joined": "已加入" }, "donate": { + "title": "捐款", "donations": "捐款", "searchDonations": "搜索捐款", "donateForThe": "为", @@ -782,9 +1115,14 @@ "yourPreviousDonations": "您之前的捐款", "donate": "捐", "nothingToShow": "这里没有什么可显示的。", - "success": "捐赠成功" + "success": "捐赠成功", + "invalidAmount": "请输入捐赠金额的数值。", + "donationAmountDescription": "请输入捐款金额的数值。", + "donationOutOfRange": "捐款金额必须在 {{min}} 和 {{max}} 之间。", + "donateTo": "捐赠给" }, "userEvents": { + "title": "活动", "nothingToShow": "这里没有什么可显示的。", "createEvent": "创建事件", "recurring": "重复事件", @@ -802,13 +1140,22 @@ "publicEvent": "是公开的", "registerable": "可注册", "monthlyCalendarView": "月历", - "yearlyCalendarView": "年历" + "yearlyCalendarView": "年历", + "search": "搜索", + "cancel": "取消", + "create": "创建", + "eventDescription": "活动描述", + "eventLocation": "活动位置", + "startDate": "开始日期", + "endDate": "结束日期" }, "userEventCard": { "starts": "开始", "ends": "结束", "creator": "创作者", - "alreadyRegistered": "已经注册" + "alreadyRegistered": "已经注册", + "location": "位置", + "register": "注册" }, "advertisement": { "title": "广告", @@ -830,11 +1177,24 @@ "deleteAdvertisement": "删除广告", "deleteAdvertisementMsg": "您想删除该广告吗?", "view": "看法", - "editAdvertisement": "编辑广告" + "editAdvertisement": "编辑广告", + "advertisementDeleted": "广告已成功删除。", + "endDateGreaterOrEqual": "结束日期应大于或等于开始日期", + "advertisementCreated": "广告已成功创建。", + "pHeading": "广告标题", + "delete": "删除", + "close": "关闭", + "no": "否", + "yes": "是", + "edit": "编辑", + "saveChanges": "保存更改", + "endOfResults": "结果结束" }, "userChat": { "chat": "聊天", - "contacts": "联系方式" + "contacts": "联系方式", + "search": "搜索", + "messages": "消息" }, "userChatRoom": { "selectContact": "选择联系人开始对话", @@ -852,20 +1212,28 @@ "String": "字符串", "Boolean": "布尔值", "Date": "日期", - "Number": "数字" + "Number": "数字", + "saveChanges": "保存更改" }, "orgActionItemCategories": { "enableButton": "使能够", "disableButton": "禁用", "updateActionItemCategory": "更新", "actionItemCategoryName": "姓名", - "actionItemCategoryDetails": "行动项目类别详细信息", + "categoryDetails": "类别详情", "enterName": "输入名字", "successfulCreation": "操作项类别创建成功", "successfulUpdation": "行动项目类别已成功更新", "sameNameConflict": "请更改名称以进行更新", "categoryEnabled": "已启用操作项类别", - "categoryDisabled": "操作项类别已禁用" + "categoryDisabled": "操作项类别已禁用", + "noActionItemCategories": "没有操作项目类别", + "status": "地位", + "categoryDeleted": "操作项目类别已成功删除", + "deleteCategory": "删除类别", + "deleteCategoryMsg": "您确定要删除此操作项目类别吗?", + "createButton": "创建按钮", + "editButton": "编辑按钮" }, "organizationVenues": { "title": "场地", @@ -889,7 +1257,12 @@ "view": "看法", "venueTitleError": "场地名称不能为空!", "venueCapacityError": "容量必须是正数!", - "searchBy": "搜索依据" + "searchBy": "搜索依据", + "description": "描述", + "edit": "编辑", + "delete": "删除", + "name": "名称", + "desc": "描述" }, "addMember": { "title": "添加会员", @@ -903,7 +1276,18 @@ "organization": "组织", "invalidDetailsMessage": "请提供所有必需的详细信息。", "passwordNotMatch": "密码不匹配。", - "addMember": "添加会员" + "firstName": "名字", + "lastName": "姓氏", + "emailAddress": "电子邮件地址", + "enterEmail": "输入电子邮件", + "password": "密码", + "enterPassword": "输入密码", + "confirmPassword": "确认密码", + "cancel": "取消", + "create": "创建", + "addMember": "添加会员", + "user": "用户", + "profile": "个人资料" }, "eventActionItems": { "title": "行动项目", @@ -911,8 +1295,8 @@ "actionItemCategory": "行动项目类别", "selectActionItemCategory": "选择操作项类别", "selectAssignee": "选择受托人", - "preCompletionNotes": "预完成注释", - "postCompletionNotes": "完成后注释", + "preCompletionNotes": "笔记", + "postCompletionNotes": "完成说明", "actionItemDetails": "行动项目详情", "dueDate": "到期日", "completionDate": "完成日期", @@ -923,6 +1307,45 @@ "successfulCreation": "操作项创建成功", "successfulUpdation": "操作项已成功更新", "notes": "笔记", - "save": "节省" + "assignee": "受让人", + "assigner": "分配者", + "assignmentDate": "任务分配日期", + "status": "地位", + "actionItemActive": "积极的", + "actionItemStatus": "行动项目状态", + "actionItemCompleted": "行动项目已完成", + "markCompletion": "标记完成", + "save": "节省", + "yes": "是", + "no": "否" + }, + "checkIn": { + "errorCheckingIn": "签到错误", + "checkedInSuccessfully": "成功签到" + }, + "eventRegistrantsModal": { + "errorAddingAttendee": "添加与会者时出错", + "errorRemovingAttendee": "删除与会者时出错" + }, + "userCampaigns": { + "title": "筹款活动", + "searchByName": "按名字搜索...", + "searchBy": "按...搜索", + "pledgers": "承诺者", + "campaigns": "活动", + "myPledges": "我的承诺", + "lowestAmount": "最低金额", + "highestAmount": "最高金额", + "lowestGoal": "最低目标", + "highestGoal": "最高目标", + "latestEndDate": "最晚结束日期", + "earliestEndDate": "最早结束日期", + "addPledge": "添加承诺", + "viewPledges": "查看承诺", + "noPledges": "未找到承诺", + "noCampaigns": "未找到活动" + }, + "userPledges": { + "title": "我的承诺" } } diff --git a/schema.graphql b/schema.graphql index b123bdb7c6..9bfd49671c 100644 --- a/schema.graphql +++ b/schema.graphql @@ -161,6 +161,15 @@ input CommentInput { text: String! } +type Community { + _id: ID! + logoUrl: String + name: String! + socialMediaUrls: SocialMediaUrls + timeout: Int + websiteLink: String +} + union ConnectionError = InvalidCursor | MaximumValueError type ConnectionPageInfo { @@ -210,7 +219,6 @@ type DirectChat { createdAt: DateTime! creator: User messages: [DirectChatMessage] - organization: Organization! updatedAt: DateTime! users: [User!]! } @@ -464,6 +472,7 @@ type Group { type GroupChat { _id: ID! + title: String! createdAt: DateTime! creator: User messages: [GroupChatMessage] @@ -527,6 +536,32 @@ enum MaritalStatus { WIDOWED } +type Chat { + _id: ID! + isGroup: Boolean! + name: String + createdAt: DateTime! + creator: User + messages: [ChatMessage] + organization: Organization + updatedAt: DateTime! + users: [User!]! + admins: [User] + lastMessageId: String +} + +type ChatMessage { + _id: ID! + createdAt: DateTime! + chatMessageBelongsTo: Chat! + messageContent: String! + type: String! + replyTo: ChatMessage + sender: User! + deletedBy: [User] + updatedAt: DateTime! +} + type MaximumLengthError implements FieldError { message: String! path: [String!]! @@ -641,6 +676,7 @@ type Mutation { data: CreateActionItemInput! ): ActionItem! createActionItemCategory( + isDisabled: Boolean! name: String! organizationId: ID! ): ActionItemCategory! @@ -655,6 +691,7 @@ type Mutation { ): Advertisement! createAgendaCategory(input: CreateAgendaCategoryInput!): AgendaCategory! createComment(data: CommentInput!, postId: ID!): Comment + createChat(data: chatInput!): Chat! createDirectChat(data: createChatInput!): DirectChat! createDonation( amount: Float! @@ -729,6 +766,7 @@ type Mutation { revokeRefreshTokenForUser: Boolean! saveFcmToken(token: String): Boolean! sendMembershipRequest(organizationId: ID!): MembershipRequest! + sendMessageToChat(chatId: ID!, messageContent: String!, type: String!, replyTo: ID): ChatMessage! sendMessageToDirectChat( chatId: ID! messageContent: String! @@ -769,6 +807,7 @@ type Mutation { ): Organization! updatePluginStatus(id: ID!, orgId: ID!): Plugin! updatePost(data: PostUpdateInput, id: ID!): Post! + updateSessionTimeout(timeout: Int!): Boolean! updateUserPassword(data: UpdateUserPasswordInput!): UserData! updateUserProfile(data: UpdateUserInput, file: String): User! updateUserRoleInOrganization( @@ -1055,8 +1094,13 @@ type Query { checkAuth: User! customDataByOrganization(organizationId: ID!): [UserCustomData!]! customFieldsByOrganization(id: ID!): [OrganizationCustomField] + chatById(id: ID!): Chat! + chatsByUserId(id: ID!): [Chat] directChatsByUserID(id: ID!): [DirectChat] directChatsMessagesByChatID(id: ID!): [DirectChatMessage] + directChatById(id: ID!): DirectChat + groupChatById(id: ID!): DirectChat + groupChatsByUserId(id: ID!): [GroupChat] event(id: ID!): Event eventVolunteersByEvent(id: ID!): [EventVolunteer] eventsByOrganization(id: ID, orderBy: EventOrderByInput): [Event] @@ -1152,8 +1196,9 @@ enum Status { type Subscription { directMessageChat: MessageChat - messageSentToDirectChat: DirectChatMessage - messageSentToGroupChat: GroupChatMessage + messageSentToChat(userId: ID!): ChatMessage + messageSentToDirectChat(userId: ID!): DirectChatMessage + messageSentToGroupChat(userId: ID!): GroupChatMessage onPluginUpdate: Plugin } @@ -1548,7 +1593,7 @@ enum WeekDays { } input createChatInput { - organizationId: ID! + organizationId: ID userIds: [ID!]! } @@ -1579,3 +1624,10 @@ input createUserFamilyInput { title: String! userIds: [ID!]! } + +input chatInput { + isGroup: Boolean! + organizationId: ID + userIds: [ID!]! + name: String +} \ No newline at end of file diff --git a/scripts/__mocks__/fileMock.js b/scripts/__mocks__/fileMock.js new file mode 100644 index 0000000000..06ad689c8b --- /dev/null +++ b/scripts/__mocks__/fileMock.js @@ -0,0 +1,2 @@ +// __mocks__/fileMock.js +module.exports = 'test-file-stub'; diff --git a/scripts/config-overrides/custom_build.js b/scripts/config-overrides/custom_build.js deleted file mode 100644 index d5c0ce93a2..0000000000 --- a/scripts/config-overrides/custom_build.js +++ /dev/null @@ -1,17 +0,0 @@ -require('dotenv').config(); -const { spawn } = require('child_process'); - -//use default react scritps config -const react_script_build = 'npx react-scripts build'; - -//use custom config overriden by react-app-rewired -const react_app_rewired_build = 'npx react-app-rewired build'; - -if (process.env.ALLOW_LOGS === "YES") { - spawn(react_app_rewired_build, { stdio: 'inherit', shell: true }); - -} -else { - spawn(react_script_build, { stdio: 'inherit', shell: true }); -} - diff --git a/scripts/config-overrides/custom_start.js b/scripts/config-overrides/custom_start.js deleted file mode 100644 index a784f1bb48..0000000000 --- a/scripts/config-overrides/custom_start.js +++ /dev/null @@ -1,19 +0,0 @@ -require('dotenv').config(); -const { spawn } = require('child_process'); - -const port = process.env.PORT || 4321; -process.env.PORT = port; - -const react_script_start = 'npx react-scripts start'; -const react_app_rewired_start = 'npx react-app-rewired start --config-overrides=scripts/config-overrides'; - -if (process.env.ALLOW_LOGS === "YES") { - // Execute the npm command - spawn(react_app_rewired_start, { stdio: 'inherit', shell: true }); - -} -else { - // Execute the npm command - spawn(react_script_start, { stdio: 'inherit', shell: true }); - } - diff --git a/scripts/config-overrides/index.js b/scripts/config-overrides/index.js deleted file mode 100644 index a8d16aa7e9..0000000000 --- a/scripts/config-overrides/index.js +++ /dev/null @@ -1,29 +0,0 @@ -const { override, addWebpackPlugin } = require('customize-cra'); -const webpack = require('webpack'); - - -module.exports = override( - // Add your new webpack plugin - addWebpackPlugin(new webpack.ProgressPlugin({ - activeModules: true, - entries: true, - handler: (percentage, message, ...args) => { - // Log a custom progress message with active module and its count - console.info(`: ${Math.floor(percentage * 100)}% ${message}`); - }, - modules: true, - modulesCount: 5000, - profile: false, - dependencies: true, - dependenciesCount: 10000, - percentBy: null, -})), - - // Modify infrastructureLogging level - (config) => { - config.infrastructureLogging = { - level: 'verbose', - }; - return config; - } -); \ No newline at end of file diff --git a/scripts/config-overrides/package.json b/scripts/config-overrides/package.json deleted file mode 100644 index c0a38b857f..0000000000 --- a/scripts/config-overrides/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "config-overrides", - "version": "1.0.0", - "type": "commonjs" -} diff --git a/scripts/test.js b/scripts/test.js deleted file mode 100644 index e5858251ff..0000000000 --- a/scripts/test.js +++ /dev/null @@ -1,52 +0,0 @@ -'use strict'; - -// Do this as the first thing so that any code reading it knows the right env. -process.env.BABEL_ENV = 'test'; -process.env.NODE_ENV = 'test'; -process.env.PUBLIC_URL = ''; - -// Makes the script crash on unhandled rejections instead of silently -// ignoring them. In the future, promise rejections that are not handled will -// terminate the Node.js process with a non-zero exit code. -process.on('unhandledRejection', (err) => { - throw err; -}); - -// Ensure environment variables are read. -import 'react-scripts/config/env.js'; - -import jest from 'jest'; -import { execSync } from 'child_process'; - -const argv = process.argv.slice(2); - -function isInGitRepository() { - try { - execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore' }); - return true; - } catch (e) { - return false; - } -} - -function isInMercurialRepository() { - try { - execSync('hg --cwd . root', { stdio: 'ignore' }); - return true; - } catch (e) { - return false; - } -} - -// Watch unless on CI or explicitly running all tests -if ( - !process.env.CI && - argv.indexOf('--watchAll') === -1 && - argv.indexOf('--watchAll=false') === -1 -) { - // https://github.com/facebook/create-react-app/issues/5210 - const hasSourceControl = isInGitRepository() || isInMercurialRepository(); - argv.push(hasSourceControl ? '--watch' : '--watchAll'); -} - -jest.run(argv); diff --git a/src/App.test.tsx b/src/App.test.tsx index b20f75e1ce..f4fba2ebf8 100644 --- a/src/App.test.tsx +++ b/src/App.test.tsx @@ -1,5 +1,5 @@ -import React from 'react'; -import { act, render, screen } from '@testing-library/react'; +import React, { act } from 'react'; +import { render, screen } from '@testing-library/react'; import { Provider } from 'react-redux'; import { MockedProvider } from '@apollo/react-testing'; import { BrowserRouter } from 'react-router-dom'; @@ -33,6 +33,7 @@ const MOCKS = [ _id: '123', firstName: 'John', lastName: 'Doe', + createdAt: '2023-04-13T04:53:17.742+00:00', image: 'john.jpg', email: 'johndoe@gmail.com', birthDate: '1990-01-01', diff --git a/src/App.tsx b/src/App.tsx index d2e5d8306e..d6e825006f 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -14,12 +14,14 @@ import OrgList from 'screens/OrgList/OrgList'; import OrgPost from 'screens/OrgPost/OrgPost'; import OrgSettings from 'screens/OrgSettings/OrgSettings'; import OrganizationActionItems from 'screens/OrganizationActionItems/OrganizationActionItems'; -import OrganizationAgendaCategory from 'screens/OrganizationAgendaCategory/OrganizationAgendaCategory'; import OrganizationDashboard from 'screens/OrganizationDashboard/OrganizationDashboard'; import OrganizationEvents from 'screens/OrganizationEvents/OrganizationEvents'; import OrganizaitionFundCampiagn from 'screens/OrganizationFundCampaign/OrganizationFundCampagins'; import OrganizationFunds from 'screens/OrganizationFunds/OrganizationFunds'; import OrganizationPeople from 'screens/OrganizationPeople/OrganizationPeople'; +import OrganizationTags from 'screens/OrganizationTags/OrganizationTags'; +import ManageTag from 'screens/ManageTag/ManageTag'; +import SubTags from 'screens/SubTags/SubTags'; import PageNotFound from 'screens/PageNotFound/PageNotFound'; import Requests from 'screens/Requests/Requests'; import Users from 'screens/Users/Users'; @@ -34,8 +36,7 @@ import Posts from 'screens/UserPortal/Posts/Posts'; import Organizations from 'screens/UserPortal/Organizations/Organizations'; import People from 'screens/UserPortal/People/People'; import Settings from 'screens/UserPortal/Settings/Settings'; -// import UserLoginPage from 'screens/UserPortal/UserLoginPage/UserLoginPage'; -// import Chat from 'screens/UserPortal/Chat/Chat'; +import Chat from 'screens/UserPortal/Chat/Chat'; import { useQuery } from '@apollo/client'; import { CHECK_AUTH } from 'GraphQl/Queries/Queries'; import Advertisements from 'components/Advertisements/Advertisements'; @@ -45,9 +46,28 @@ import FundCampaignPledge from 'screens/FundCampaignPledge/FundCampaignPledge'; import useLocalStorage from 'utils/useLocalstorage'; import UserScreen from 'screens/UserPortal/UserScreen/UserScreen'; import EventDashboardScreen from 'components/EventDashboardScreen/EventDashboardScreen'; +import Campaigns from 'screens/UserPortal/Campaigns/Campaigns'; +import Pledges from 'screens/UserPortal/Pledges/Pledges'; const { setItem } = useLocalStorage(); +/** + * This is the main function for our application. It sets up all the routes and components, + * defining how the user can navigate through the app. The function uses React Router's `Routes` + * and `Route` components to map different URL paths to corresponding screens and components. + * + * ## Important Details + * - **UseEffect Hook**: This hook checks user authentication status using the `CHECK_AUTH` GraphQL query. + * - **Plugins**: It dynamically loads additional routes for any installed plugins. + * - **Routes**: + * - The root route ("/") takes the user to the `LoginPage`. + * - Protected routes are wrapped with the `SecuredRoute` component to ensure they are only accessible to authenticated users. + * - Admin and Super Admin routes allow access to organization and user management screens. + * - User portal routes allow end-users to interact with organizations, settings, chat, events, etc. + * + * @returns The rendered routes and components of the application. + */ + function app(): JSX.Element { /*const { updatePluginLinks, updateInstalled } = bindActionCreators( actionCreators, @@ -100,12 +120,12 @@ function app(): JSX.Element { ], index: number, ) => { - const extraComponent = plugin[1]; + const ExtraComponent = plugin[1]; return ( } /> ); }, @@ -126,6 +146,12 @@ function app(): JSX.Element { } /> } /> } /> + } /> + } + /> + } /> } /> } /> } /> - } - /> } /> }> } /> } /> + } /> }> } /> } /> } /> } /> } /> + } /> + } /> }> notebook diff --git a/src/assets/svgs/angleLeft.svg b/src/assets/svgs/angleLeft.svg deleted file mode 100644 index a0362e5e38..0000000000 --- a/src/assets/svgs/angleLeft.svg +++ /dev/null @@ -1,5 +0,0 @@ - - -angle-left - - \ No newline at end of file diff --git a/src/assets/svgs/chat.svg b/src/assets/svgs/chat.svg new file mode 100644 index 0000000000..72787fab78 --- /dev/null +++ b/src/assets/svgs/chat.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/svgs/eventDashboard.svg b/src/assets/svgs/eventDashboard.svg deleted file mode 100644 index 769c57d315..0000000000 --- a/src/assets/svgs/eventDashboard.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/src/assets/svgs/eventStats.svg b/src/assets/svgs/eventStats.svg deleted file mode 100644 index ffa43fdc4a..0000000000 --- a/src/assets/svgs/eventStats.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/src/assets/svgs/newChat.svg b/src/assets/svgs/newChat.svg new file mode 100644 index 0000000000..e3609e2895 --- /dev/null +++ b/src/assets/svgs/newChat.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/svgs/social-icons/Twitter-Logo.svg b/src/assets/svgs/social-icons/X-Logo.svg similarity index 100% rename from src/assets/svgs/social-icons/Twitter-Logo.svg rename to src/assets/svgs/social-icons/X-Logo.svg diff --git a/src/assets/svgs/social-icons/index.tsx b/src/assets/svgs/social-icons/index.tsx index af6ef77966..20544051e5 100644 --- a/src/assets/svgs/social-icons/index.tsx +++ b/src/assets/svgs/social-icons/index.tsx @@ -3,7 +3,7 @@ import GithubLogo from './Github-Logo.svg'; import InstagramLogo from './Instagram-Logo.svg'; import LinkedInLogo from './Linkedin-Logo.svg'; import SlackLogo from './Slack-Logo.svg'; -import TwitterLogo from './Twitter-Logo.svg'; +import XLogo from './X-Logo.svg'; import YoutubeLogo from './Youtube-Logo.svg'; import RedditLogo from './Reddit-Logo.svg'; @@ -13,7 +13,7 @@ export { InstagramLogo, LinkedInLogo, SlackLogo, - TwitterLogo, + XLogo, YoutubeLogo, RedditLogo, }; diff --git a/src/assets/svgs/tag.svg b/src/assets/svgs/tag.svg new file mode 100644 index 0000000000..e3646993be --- /dev/null +++ b/src/assets/svgs/tag.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/components/ActionItems/ActionItemsContainer.module.css b/src/components/ActionItems/ActionItemsContainer.module.css deleted file mode 100644 index b55328c563..0000000000 --- a/src/components/ActionItems/ActionItemsContainer.module.css +++ /dev/null @@ -1,25 +0,0 @@ -.actionItemStatusBadge { - width: 5.5rem; - margin-left: 1.1rem; -} - -.createModal { - margin-top: 20vh; - margin-left: 13vw; - max-width: 80vw; -} - -.titlemodal { - color: var(--bs-gray-600); - font-weight: 600; - font-size: 20px; - margin-bottom: 20px; - padding-bottom: 5px; - border-bottom: 3px solid var(--bs-primary); - width: 65%; -} - -.actionItemsOptionsButton { - width: 24px; - height: 24px; -} diff --git a/src/components/ActionItems/ActionItemsContainer.test.tsx b/src/components/ActionItems/ActionItemsContainer.test.tsx deleted file mode 100644 index dda9e07035..0000000000 --- a/src/components/ActionItems/ActionItemsContainer.test.tsx +++ /dev/null @@ -1,670 +0,0 @@ -import React from 'react'; -import { - render, - screen, - fireEvent, - waitFor, - act, - waitForElementToBeRemoved, -} from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import 'jest-localstorage-mock'; -import { MockedProvider } from '@apollo/client/testing'; -import 'jest-location-mock'; -import { I18nextProvider } from 'react-i18next'; -import { Provider } from 'react-redux'; -import { BrowserRouter } from 'react-router-dom'; -import i18nForTest from 'utils/i18nForTest'; -import { toast } from 'react-toastify'; -import { LocalizationProvider } from '@mui/x-date-pickers'; -import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; - -import { store } from 'state/store'; -import { StaticMockLink } from 'utils/StaticMockLink'; - -import ActionItemsContainer from './ActionItemsContainer'; -import { props, props2 } from './ActionItemsContainerProps'; -import { MOCKS, MOCKS_ERROR_MUTATIONS } from './ActionItemsContainerMocks'; - -const link = new StaticMockLink(MOCKS, true); -const link2 = new StaticMockLink(MOCKS_ERROR_MUTATIONS, true); - -jest.mock('react-toastify', () => ({ - toast: { - success: jest.fn(), - error: jest.fn(), - }, -})); - -jest.mock('@mui/x-date-pickers/DateTimePicker', () => { - return { - DateTimePicker: jest.requireActual( - '@mui/x-date-pickers/DesktopDateTimePicker', - ).DesktopDateTimePicker, - }; -}); - -async function wait(ms = 100): Promise { - await act(() => { - return new Promise((resolve) => { - setTimeout(resolve, ms); - }); - }); -} - -const translations = JSON.parse( - JSON.stringify( - i18nForTest.getDataByLanguage('en')?.translation.organizationActionItems, - ), -); - -describe('Testing Action Item Categories Component', () => { - const formData = { - assignee: 'Scott Norris', - preCompletionNotes: 'pre completion notes edited', - dueDate: '02/14/2024', - completionDate: '02/21/2024', - }; - - test('component loads correctly with action items', async () => { - render( - - - - - - - - - , - ); - - await wait(); - - await waitFor(() => { - expect( - screen.queryByText(translations.noActionItems), - ).not.toBeInTheDocument(); - }); - }); - - test('component loads correctly with no action items', async () => { - render( - - - - - - - - - , - ); - - await wait(); - - await waitFor(() => { - expect( - screen.queryByText(translations.noActionItems), - ).toBeInTheDocument(); - }); - }); - - test('opens and closes the update modal correctly', async () => { - render( - - - - - - - - - - - , - ); - - await wait(); - - await waitFor(() => { - expect( - screen.getAllByTestId('editActionItemModalBtn')[0], - ).toBeInTheDocument(); - }); - userEvent.click(screen.getAllByTestId('editActionItemModalBtn')[0]); - - await waitFor(() => { - return expect( - screen.findByTestId('updateActionItemModalCloseBtn'), - ).resolves.toBeInTheDocument(); - }); - userEvent.click(screen.getByTestId('updateActionItemModalCloseBtn')); - - await waitForElementToBeRemoved(() => - screen.queryByTestId('updateActionItemModalCloseBtn'), - ); - }); - - test('opens and closes the action item status change modal correctly', async () => { - render( - - - - - - - - - - - , - ); - - await wait(); - - await waitFor(() => { - expect( - screen.getAllByTestId('actionItemStatusChangeCheckbox')[0], - ).toBeInTheDocument(); - }); - userEvent.click(screen.getAllByTestId('actionItemStatusChangeCheckbox')[0]); - - await waitFor(() => { - return expect( - screen.findByTestId('actionItemStatusChangeModalCloseBtn'), - ).resolves.toBeInTheDocument(); - }); - userEvent.click(screen.getByTestId('actionItemStatusChangeModalCloseBtn')); - - await waitForElementToBeRemoved(() => - screen.queryByTestId('actionItemStatusChangeModalCloseBtn'), - ); - }); - - test('opens and closes the preview modal correctly', async () => { - render( - - - - - - - - - - - , - ); - - await wait(); - - await waitFor(() => { - expect( - screen.getAllByTestId('previewActionItemModalBtn')[0], - ).toBeInTheDocument(); - }); - userEvent.click(screen.getAllByTestId('previewActionItemModalBtn')[0]); - - await waitFor(() => { - return expect( - screen.findByTestId('previewActionItemModalCloseBtn'), - ).resolves.toBeInTheDocument(); - }); - userEvent.click(screen.getByTestId('previewActionItemModalCloseBtn')); - - await waitForElementToBeRemoved(() => - screen.queryByTestId('previewActionItemModalCloseBtn'), - ); - }); - - test('opens and closes the update and delete modals through the preview modal', async () => { - render( - - - - - - - - - - - , - ); - - await wait(); - - await waitFor(() => { - expect( - screen.getAllByTestId('previewActionItemModalBtn')[0], - ).toBeInTheDocument(); - }); - userEvent.click(screen.getAllByTestId('previewActionItemModalBtn')[0]); - - await waitFor(() => { - return expect( - screen.findByTestId('previewActionItemModalCloseBtn'), - ).resolves.toBeInTheDocument(); - }); - - await waitFor(() => { - expect( - screen.getByTestId('deleteActionItemPreviewModalBtn'), - ).toBeInTheDocument(); - }); - userEvent.click(screen.getByTestId('deleteActionItemPreviewModalBtn')); - - await waitFor(() => { - return expect( - screen.findByTestId('actionItemDeleteModalCloseBtn'), - ).resolves.toBeInTheDocument(); - }); - userEvent.click(screen.getByTestId('actionItemDeleteModalCloseBtn')); - - await waitForElementToBeRemoved(() => - screen.queryByTestId('actionItemDeleteModalCloseBtn'), - ); - - await waitFor(() => { - expect( - screen.getByTestId('editActionItemPreviewModalBtn'), - ).toBeInTheDocument(); - }); - userEvent.click(screen.getByTestId('editActionItemPreviewModalBtn')); - - await waitFor(() => { - return expect( - screen.findByTestId('updateActionItemModalCloseBtn'), - ).resolves.toBeInTheDocument(); - }); - userEvent.click(screen.getByTestId('updateActionItemModalCloseBtn')); - - await waitForElementToBeRemoved(() => - screen.queryByTestId('updateActionItemModalCloseBtn'), - ); - }); - - test('updates an action item and toasts success', async () => { - render( - - - - - - - - - - - , - ); - - await wait(); - - await waitFor(() => { - expect( - screen.getAllByTestId('editActionItemModalBtn')[0], - ).toBeInTheDocument(); - }); - userEvent.click(screen.getAllByTestId('editActionItemModalBtn')[0]); - - await waitFor(() => { - expect(screen.getByTestId('formUpdateAssignee')).toBeInTheDocument(); - }); - - userEvent.selectOptions( - screen.getByTestId('formUpdateAssignee'), - formData.assignee, - ); - - const preCompletionNotes = screen.getByPlaceholderText( - translations.preCompletionNotes, - ); - fireEvent.change(preCompletionNotes, { target: { value: '' } }); - userEvent.type(preCompletionNotes, formData.preCompletionNotes); - - // const postCompletionNotes = screen.getByPlaceholderText( - // translations.postCompletionNotes, - // ); - // fireEvent.change(postCompletionNotes, { target: { value: '' } }); - // userEvent.type(postCompletionNotes, formData.postCompletionNotes); - - const dueDatePicker = screen.getByLabelText(translations.dueDate); - fireEvent.change(dueDatePicker, { - target: { value: formData.dueDate }, - }); - - const completionDatePicker = screen.getByLabelText( - translations.completionDate, - ); - fireEvent.change(completionDatePicker, { - target: { value: formData.completionDate }, - }); - - // await waitFor(() => { - // expect(screen.getByTestId('alldayCheck')).toBeInTheDocument(); - // }); - // userEvent.click(screen.getByTestId('alldayCheck')); - - await waitFor(() => { - expect(screen.getByTestId('editActionItemBtn')).toBeInTheDocument(); - }); - userEvent.click(screen.getByTestId('editActionItemBtn')); - - await waitFor(() => { - expect(toast.success).toBeCalledWith(translations.successfulUpdation); - }); - }); - - test('toasts error on unsuccessful updation', async () => { - render( - - - - - - - - - - - , - ); - - await wait(); - - await waitFor(() => { - expect( - screen.getAllByTestId('editActionItemModalBtn')[0], - ).toBeInTheDocument(); - }); - userEvent.click(screen.getAllByTestId('editActionItemModalBtn')[0]); - - await waitFor(() => { - expect(screen.getByTestId('formUpdateAssignee')).toBeInTheDocument(); - }); - - userEvent.selectOptions( - screen.getByTestId('formUpdateAssignee'), - formData.assignee, - ); - - const preCompletionNotes = screen.getByPlaceholderText( - translations.preCompletionNotes, - ); - fireEvent.change(preCompletionNotes, { target: { value: '' } }); - userEvent.type(preCompletionNotes, formData.preCompletionNotes); - - // const postCompletionNotes = screen.getByPlaceholderText( - // translations.postCompletionNotes, - // ); - // fireEvent.change(postCompletionNotes, { target: { value: '' } }); - // userEvent.type(postCompletionNotes, formData.postCompletionNotes); - - const dueDatePicker = screen.getByLabelText(translations.dueDate); - fireEvent.change(dueDatePicker, { - target: { value: formData.dueDate }, - }); - - const completionDatePicker = screen.getByLabelText( - translations.completionDate, - ); - fireEvent.change(completionDatePicker, { - target: { value: formData.completionDate }, - }); - - // await waitFor(() => { - // expect(screen.getByTestId('alldayCheck')).toBeInTheDocument(); - // }); - // userEvent.click(screen.getByTestId('alldayCheck')); - - await waitFor(() => { - expect(screen.getByTestId('editActionItemBtn')).toBeInTheDocument(); - }); - userEvent.click(screen.getByTestId('editActionItemBtn')); - - await waitFor(() => { - expect(toast.error).toHaveBeenCalled(); - }); - }); - - test('updates an action item status through the action item status change modal', async () => { - render( - - - - - - - - - - - , - ); - - await wait(); - - await waitFor(() => { - expect( - screen.getAllByTestId('actionItemStatusChangeCheckbox')[0], - ).toBeInTheDocument(); - }); - userEvent.click(screen.getAllByTestId('actionItemStatusChangeCheckbox')[0]); - - await waitFor(() => { - expect( - screen.getByTestId('actionItemsStatusChangeNotes'), - ).toBeInTheDocument(); - }); - - const postCompletionNotes = screen.getByTestId( - 'actionItemsStatusChangeNotes', - ); - fireEvent.change(postCompletionNotes, { target: { value: '' } }); - userEvent.type( - postCompletionNotes, - 'this action item has been completed successfully', - ); - - await waitFor(() => { - expect( - screen.getByTestId('actionItemStatusChangeSubmitBtn'), - ).toBeInTheDocument(); - }); - userEvent.click(screen.getByTestId('actionItemStatusChangeSubmitBtn')); - - await waitFor(() => { - expect(toast.success).toBeCalledWith(translations.successfulUpdation); - }); - - await waitFor(() => { - expect( - screen.getAllByTestId('actionItemStatusChangeCheckbox')[1], - ).toBeInTheDocument(); - }); - userEvent.click(screen.getAllByTestId('actionItemStatusChangeCheckbox')[1]); - - await waitFor(() => { - expect( - screen.getByTestId('actionItemsStatusChangeNotes'), - ).toBeInTheDocument(); - }); - - const preCompletionNotes = screen.getByTestId( - 'actionItemsStatusChangeNotes', - ); - fireEvent.change(preCompletionNotes, { target: { value: '' } }); - userEvent.type( - preCompletionNotes, - 'this action item has been made active again', - ); - - await waitFor(() => { - expect( - screen.getByTestId('actionItemStatusChangeSubmitBtn'), - ).toBeInTheDocument(); - }); - userEvent.click(screen.getByTestId('actionItemStatusChangeSubmitBtn')); - - await waitFor(() => { - expect(toast.success).toBeCalledWith(translations.successfulUpdation); - }); - }); - - test('deletes the action item and toasts success', async () => { - render( - - - - - - - - - - - , - ); - - await wait(); - - await waitFor(() => { - expect( - screen.getAllByTestId('previewActionItemModalBtn')[0], - ).toBeInTheDocument(); - }); - userEvent.click(screen.getAllByTestId('previewActionItemModalBtn')[0]); - - await waitFor(() => { - return expect( - screen.findByTestId('previewActionItemModalCloseBtn'), - ).resolves.toBeInTheDocument(); - }); - - await waitFor(() => { - expect( - screen.getByTestId('deleteActionItemPreviewModalBtn'), - ).toBeInTheDocument(); - }); - userEvent.click(screen.getByTestId('deleteActionItemPreviewModalBtn')); - - await waitFor(() => { - return expect( - screen.findByTestId('actionItemDeleteModalCloseBtn'), - ).resolves.toBeInTheDocument(); - }); - - userEvent.click(screen.getByTestId('deleteActionItemBtn')); - - await waitFor(() => { - expect(toast.success).toBeCalledWith(translations.successfulDeletion); - }); - }); - - test('toasts error on unsuccessful deletion', async () => { - render( - - - - - - - - - - - , - ); - - await wait(); - - await waitFor(() => { - expect( - screen.getAllByTestId('previewActionItemModalBtn')[0], - ).toBeInTheDocument(); - }); - userEvent.click(screen.getAllByTestId('previewActionItemModalBtn')[0]); - - await waitFor(() => { - return expect( - screen.findByTestId('previewActionItemModalCloseBtn'), - ).resolves.toBeInTheDocument(); - }); - - await waitFor(() => { - expect( - screen.getByTestId('deleteActionItemPreviewModalBtn'), - ).toBeInTheDocument(); - }); - userEvent.click(screen.getByTestId('deleteActionItemPreviewModalBtn')); - - await waitFor(() => { - return expect( - screen.findByTestId('actionItemDeleteModalCloseBtn'), - ).resolves.toBeInTheDocument(); - }); - userEvent.click(screen.getByTestId('deleteActionItemBtn')); - - await waitFor(() => { - expect(toast.error).toHaveBeenCalled(); - }); - }); - - test('shows the overlay text on action item notes', async () => { - const { getAllByTestId } = render( - - - - - - - - - - - , - ); - - await wait(); - - await waitFor(() => { - expect( - screen.getAllByTestId('actionItemPreCompletionNotesOverlay')[0], - ).toBeInTheDocument(); - }); - - await waitFor(() => { - fireEvent.mouseEnter( - getAllByTestId('actionItemPreCompletionNotesOverlay')[0], - ); - }); - - await waitFor(() => { - expect(screen.getByTestId('popover-actionItem1')).toBeInTheDocument(); - }); - - await waitFor(() => { - fireEvent.mouseLeave( - getAllByTestId('actionItemPreCompletionNotesOverlay')[0], - ); - }); - - await waitFor(() => { - fireEvent.mouseEnter( - getAllByTestId('actionItemPostCompletionNotesOverlay')[0], - ); - }); - - await waitFor(() => { - expect(screen.getByTestId('popover-actionItem2')).toBeInTheDocument(); - }); - - await waitFor(() => { - fireEvent.mouseLeave( - getAllByTestId('actionItemPostCompletionNotesOverlay')[0], - ); - }); - }); -}); diff --git a/src/components/ActionItems/ActionItemsContainer.tsx b/src/components/ActionItems/ActionItemsContainer.tsx deleted file mode 100644 index 0cb799c212..0000000000 --- a/src/components/ActionItems/ActionItemsContainer.tsx +++ /dev/null @@ -1,463 +0,0 @@ -import React, { useState } from 'react'; -import dayjs from 'dayjs'; -import type { ChangeEvent } from 'react'; -import { - Button, - Col, - Form, - Modal, - OverlayTrigger, - Popover, - Row, -} from 'react-bootstrap'; -import { useTranslation } from 'react-i18next'; -import { toast } from 'react-toastify'; - -import { - DELETE_ACTION_ITEM_MUTATION, - UPDATE_ACTION_ITEM_MUTATION, -} from 'GraphQl/Mutations/mutations'; -import { useMutation } from '@apollo/client'; - -import type { - InterfaceActionItemInfo, - InterfaceMemberInfo, -} from 'utils/interfaces'; -import styles from './ActionItemsContainer.module.css'; -import ActionItemUpdateModal from '../../screens/OrganizationActionItems/ActionItemUpdateModal'; -import ActionItemPreviewModal from '../../screens/OrganizationActionItems/ActionItemPreviewModal'; -import ActionItemDeleteModal from '../../screens/OrganizationActionItems/ActionItemDeleteModal'; - -function actionItemsContainer({ - actionItemsConnection, - actionItemsData, - membersData, - actionItemsRefetch, -}: { - actionItemsConnection: 'Organization' | 'Event'; - actionItemsData: InterfaceActionItemInfo[] | undefined; - membersData: InterfaceMemberInfo[] | undefined; - actionItemsRefetch: () => void; -}): JSX.Element { - const { t } = useTranslation('translation', { - keyPrefix: 'organizationActionItems', - }); - const { t: tCommon } = useTranslation('common'); - - const [actionItemPreviewModalIsOpen, setActionItemPreviewModalIsOpen] = - useState(false); - const [actionItemUpdateModalIsOpen, setActionItemUpdateModalIsOpen] = - useState(false); - const [actionItemDeleteModalIsOpen, setActionItemDeleteModalIsOpen] = - useState(false); - const [actionItemStatusModal, setActionItemStatusModal] = useState(false); - const [isActionItemCompleted, setIsActionItemCompleted] = useState(false); - - const [assignmentDate, setAssignmentDate] = useState(new Date()); - const [dueDate, setDueDate] = useState(new Date()); - const [completionDate, setCompletionDate] = useState(new Date()); - const [actionItemId, setActionItemId] = useState(''); - const [actionItemNotes, setActionItemNotes] = useState(''); - - const [formState, setFormState] = useState({ - assignee: '', - assigner: '', - assigneeId: '', - preCompletionNotes: '', - postCompletionNotes: '', - isCompleted: false, - }); - - const showPreviewModal = (actionItem: InterfaceActionItemInfo): void => { - setActionItemState(actionItem); - setActionItemPreviewModalIsOpen(true); - }; - - const showUpdateModal = (): void => { - setActionItemUpdateModalIsOpen(!actionItemUpdateModalIsOpen); - }; - - const hidePreviewModal = (): void => { - setActionItemPreviewModalIsOpen(false); - }; - - const hideUpdateModal = (): void => { - setActionItemId(''); - setActionItemUpdateModalIsOpen(!actionItemUpdateModalIsOpen); - }; - - const toggleDeleteModal = (): void => { - setActionItemDeleteModalIsOpen(!actionItemDeleteModalIsOpen); - }; - - const [updateActionItem] = useMutation(UPDATE_ACTION_ITEM_MUTATION); - - const updateActionItemHandler = async ( - e: ChangeEvent, - ): Promise => { - e.preventDefault(); - try { - await updateActionItem({ - variables: { - actionItemId, - assigneeId: formState.assigneeId, - preCompletionNotes: formState.preCompletionNotes, - postCompletionNotes: formState.postCompletionNotes, - dueDate: dayjs(dueDate).format('YYYY-MM-DD'), - completionDate: dayjs(completionDate).format('YYYY-MM-DD'), - isCompleted: formState.isCompleted, - }, - }); - - actionItemsRefetch(); - hideUpdateModal(); - toast.success(t('successfulUpdation')); - } catch (error: unknown) { - if (error instanceof Error) { - toast.error(error.message); - console.log(error.message); - } - } - }; - - const [removeActionItem] = useMutation(DELETE_ACTION_ITEM_MUTATION); - const deleteActionItemHandler = async (): Promise => { - try { - await removeActionItem({ - variables: { - actionItemId, - }, - }); - - actionItemsRefetch(); - toggleDeleteModal(); - toast.success(t('successfulDeletion')); - } catch (error: unknown) { - if (error instanceof Error) { - toast.error(error.message); - console.log(error.message); - } - } - }; - - const handleEditClick = (actionItem: InterfaceActionItemInfo): void => { - setActionItemState(actionItem); - showUpdateModal(); - }; - - const handleActionItemStatusChange = ( - actionItem: InterfaceActionItemInfo, - ): void => { - actionItem = { ...actionItem, isCompleted: !actionItem.isCompleted }; - setIsActionItemCompleted(!actionItem.isCompleted); - setActionItemState(actionItem); - setActionItemStatusModal(true); - }; - - const hideActionItemStatusModal = (): void => { - setActionItemStatusModal(false); - }; - - const setActionItemState = (actionItem: InterfaceActionItemInfo): void => { - setFormState({ - ...formState, - assignee: `${actionItem.assignee.firstName} ${actionItem.assignee.lastName}`, - assigner: `${actionItem.assigner.firstName} ${actionItem.assigner.lastName}`, - assigneeId: actionItem.assignee._id, - preCompletionNotes: actionItem.preCompletionNotes, - postCompletionNotes: actionItem.postCompletionNotes, - isCompleted: actionItem.isCompleted, - }); - setActionItemId(actionItem._id); - setDueDate(actionItem.dueDate); - setAssignmentDate(actionItem.assignmentDate); - setCompletionDate(actionItem.completionDate); - }; - - const popover = ( - - {actionItemNotes} - - ); - - return ( - <> -
-
- - -
{t('assignee')}
- - - {t('actionItemCategory')} - - -
{t('preCompletionNotes')}
- - -
{t('postCompletionNotes')}
- - -
{t('options')}
- -
-
- -
- {actionItemsData?.map((actionItem, index) => ( -
- - - {`${actionItem.assignee.firstName} ${actionItem.assignee.lastName}`} - - - {actionItem.actionItemCategory.name} - - -
- - { - setActionItemId(actionItem._id); - setActionItemNotes(actionItem.preCompletionNotes); - }} - > - {actionItem.preCompletionNotes.length > 25 - ? `${actionItem.preCompletionNotes.substring(0, 25)}...` - : actionItem.preCompletionNotes} - - -
- - -
- {actionItem.isCompleted ? ( - - { - setActionItemId(actionItem._id); - setActionItemNotes(actionItem.postCompletionNotes); - }} - className="ms-3 " - > - {actionItem.postCompletionNotes?.length > 25 - ? `${actionItem.postCompletionNotes.substring(0, 25)}...` - : actionItem.postCompletionNotes} - - - ) : ( - - {t('actionItemActive')} - - )} -
- - -
- handleActionItemStatusChange(actionItem)} - /> - - -
- -
- - {index !== actionItemsData.length - 1 &&
} -
- ))} - - {actionItemsData?.length === 0 && ( -
- {t('noActionItems')} -
- )} -
-
- - {/* action item status change modal */} - - -

{t('actionItemStatus')}

- -
- -
- - {isActionItemCompleted - ? t('preCompletionNotes') - : t('postCompletionNotes')} - - { - if (isActionItemCompleted) { - setFormState({ - ...formState, - preCompletionNotes: e.target.value, - }); - } else { - setFormState({ - ...formState, - postCompletionNotes: e.target.value, - }); - } - }} - /> - - -
-
- - {/* preview modal */} - - - {/* Update Modal */} - - - {/* Delete Modal */} - - - ); -} - -export default actionItemsContainer; diff --git a/src/components/ActionItems/ActionItemsContainerMocks.ts b/src/components/ActionItems/ActionItemsContainerMocks.ts deleted file mode 100644 index a2dc20c5eb..0000000000 --- a/src/components/ActionItems/ActionItemsContainerMocks.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { - UPDATE_ACTION_ITEM_MUTATION, - DELETE_ACTION_ITEM_MUTATION, -} from 'GraphQl/Mutations/mutations'; - -export const MOCKS = [ - { - request: { - query: UPDATE_ACTION_ITEM_MUTATION, - variables: { - actionItemId: 'actionItem1', - assigneeId: 'user2', - preCompletionNotes: 'pre completion notes edited', - postCompletionNotes: 'Post Completion Notes', - dueDate: '2024-02-14', - completionDate: '2024-02-21', - isCompleted: false, - }, - }, - result: { - data: { - updateActionItem: { - _id: 'actionItem1', - }, - }, - }, - }, - { - request: { - query: UPDATE_ACTION_ITEM_MUTATION, - variables: { - actionItemId: 'actionItem1', - assigneeId: 'user1', - preCompletionNotes: 'Pre Completion Notes', - postCompletionNotes: 'this action item has been completed successfully', - dueDate: '2024-02-21', - completionDate: '2024-02-21', - isCompleted: true, - }, - }, - result: { - data: { - updateActionItem: { - _id: 'actionItem1', - }, - }, - }, - }, - { - request: { - query: UPDATE_ACTION_ITEM_MUTATION, - variables: { - actionItemId: 'actionItem2', - assigneeId: 'user1', - preCompletionNotes: 'this action item has been made active again', - postCompletionNotes: 'Post Completion Notes', - dueDate: '2024-02-21', - completionDate: '2024-02-21', - isCompleted: false, - }, - }, - result: { - data: { - updateActionItem: { - _id: 'actionItem1', - }, - }, - }, - }, - { - request: { - query: DELETE_ACTION_ITEM_MUTATION, - variables: { - actionItemId: 'actionItem1', - }, - }, - result: { - data: { - removeActionItem: { - _id: 'actionItem1', - }, - }, - }, - }, -]; - -export const MOCKS_ERROR_MUTATIONS = [ - { - request: { - query: UPDATE_ACTION_ITEM_MUTATION, - variables: { - actionItemId: 'actionItem1', - assigneeId: 'user2', - preCompletionNotes: 'pre completion notes edited', - postCompletionNotes: '', - dueDate: '2024-02-14', - completionDate: '2024-02-21', - isCompleted: false, - }, - }, - error: new Error('Mock Graphql Error'), - }, - { - request: { - query: DELETE_ACTION_ITEM_MUTATION, - variables: { - actionItemId: 'actionItem1', - }, - }, - error: new Error('Mock Graphql Error'), - }, -]; diff --git a/src/components/ActionItems/ActionItemsContainerProps.ts b/src/components/ActionItems/ActionItemsContainerProps.ts deleted file mode 100644 index 19ba6f6369..0000000000 --- a/src/components/ActionItems/ActionItemsContainerProps.ts +++ /dev/null @@ -1,131 +0,0 @@ -type ActionItemsConnectionType = 'Organization' | 'Event'; - -export const props = { - actionItemsConnection: 'Organization' as ActionItemsConnectionType, - actionItemsData: [ - { - _id: 'actionItem1', - assignee: { - _id: 'user1', - firstName: 'Harve', - lastName: 'Lance', - }, - actionItemCategory: { - _id: 'actionItemCategory1', - name: 'ActionItemCategory 1', - }, - preCompletionNotes: 'Pre Completion Notes', - postCompletionNotes: 'Post Completion Notes', - assignmentDate: new Date('2024-02-14'), - dueDate: new Date('2024-02-21'), - completionDate: new Date('2024-02-21'), - isCompleted: false, - assigner: { - _id: 'user0', - firstName: 'Wilt', - lastName: 'Shepherd', - }, - event: { - _id: 'event1', - title: 'event 1', - }, - creator: { - _id: 'user0', - firstName: 'Wilt', - lastName: 'Shepherd', - }, - }, - { - _id: 'actionItem2', - assignee: { - _id: 'user1', - firstName: 'Harve', - lastName: 'Lance', - }, - actionItemCategory: { - _id: 'actionItemCategory1', - name: 'ActionItemCategory 1', - }, - preCompletionNotes: 'Pre Completion Notes', - postCompletionNotes: 'Post Completion Notes', - assignmentDate: new Date('2024-02-14'), - dueDate: new Date('2024-02-21'), - completionDate: new Date('2024-02-21'), - isCompleted: true, - assigner: { - _id: 'user0', - firstName: 'Wilt', - lastName: 'Shepherd', - }, - event: { - _id: 'event1', - title: 'event 1', - }, - creator: { - _id: 'user0', - firstName: 'Wilt', - lastName: 'Shepherd', - }, - }, - { - _id: 'actionItem3', - assignee: { - _id: 'user1', - firstName: 'Harve', - lastName: 'Lance', - }, - actionItemCategory: { - _id: 'actionItemCategory1', - name: 'ActionItemCategory 1', - }, - preCompletionNotes: 'Pre Completion Notes more than 25 characters', - postCompletionNotes: 'Post Completion Notes more than 25 characters', - assignmentDate: new Date('2024-02-14'), - dueDate: new Date('2024-02-21'), - completionDate: new Date('2024-02-21'), - isCompleted: true, - assigner: { - _id: 'user0', - firstName: 'Wilt', - lastName: 'Shepherd', - }, - event: { - _id: 'event1', - title: 'event 1', - }, - creator: { - _id: 'user0', - firstName: 'Wilt', - lastName: 'Shepherd', - }, - }, - ], - membersData: [ - { - _id: 'user1', - firstName: 'Harve', - lastName: 'Lance', - email: 'harve@example.com', - image: '', - organizationsBlockedBy: [], - createdAt: '2024-02-14', - }, - { - _id: 'user2', - firstName: 'Scott', - lastName: 'Norris', - email: 'scott@example.com', - image: '', - organizationsBlockedBy: [], - createdAt: '2024-02-14', - }, - ], - actionItemsRefetch: jest.fn(), -}; - -export const props2 = { - actionItemsConnection: 'Organization' as ActionItemsConnectionType, - actionItemsData: [], - membersData: [], - actionItemsRefetch: jest.fn(), -}; diff --git a/src/components/ActionItems/ActionItemsModal.test.tsx b/src/components/ActionItems/ActionItemsModal.test.tsx deleted file mode 100644 index 01a15ee6aa..0000000000 --- a/src/components/ActionItems/ActionItemsModal.test.tsx +++ /dev/null @@ -1,294 +0,0 @@ -import React from 'react'; -import { - act, - fireEvent, - render, - screen, - waitFor, -} from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import { MockedProvider } from '@apollo/react-testing'; -import { ActionItemsModal } from './ActionItemsModal'; -import { BrowserRouter } from 'react-router-dom'; -import { Provider } from 'react-redux'; -import { store } from 'state/store'; -import { I18nextProvider } from 'react-i18next'; -import i18nForTest from 'utils/i18nForTest'; -import { LocalizationProvider } from '@mui/x-date-pickers'; -import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; -import { toast } from 'react-toastify'; - -import { - MOCKS_ERROR_ACTION_ITEM_CATEGORY_LIST_QUERY, - MOCKS_ERROR_ACTION_ITEM_LIST_QUERY, - MOCKS_ERROR_MEMBERS_LIST_QUERY, - MOCKS_ERROR_MUTATIONS, -} from '../../screens/OrganizationActionItems/OrganizationActionItemsErrorMocks'; -import { MOCKS } from '../../screens/OrganizationActionItems/OrganizationActionItemMocks'; -import { StaticMockLink } from 'utils/StaticMockLink'; - -jest.mock('react-toastify', () => ({ - toast: { - success: jest.fn(), - error: jest.fn(), - }, -})); - -jest.mock('@mui/x-date-pickers/DateTimePicker', () => { - return { - DateTimePicker: jest.requireActual( - '@mui/x-date-pickers/DesktopDateTimePicker', - ).DesktopDateTimePicker, - }; -}); - -async function wait(ms = 100): Promise { - await act(() => { - return new Promise((resolve) => { - setTimeout(resolve, ms); - }); - }); -} - -const link = new StaticMockLink(MOCKS, true); -const link2 = new StaticMockLink( - MOCKS_ERROR_ACTION_ITEM_CATEGORY_LIST_QUERY, - true, -); -const link3 = new StaticMockLink(MOCKS_ERROR_MEMBERS_LIST_QUERY, true); -const link4 = new StaticMockLink(MOCKS_ERROR_ACTION_ITEM_LIST_QUERY, true); -const link5 = new StaticMockLink(MOCKS_ERROR_MUTATIONS, true); - -const translations = JSON.parse( - JSON.stringify( - i18nForTest.getDataByLanguage('en')?.translation.organizationActionItems, - ), -); - -describe('Testing Check In Attendees Modal', () => { - const formData = { - actionItemCategory: 'ActionItemCategory 1', - assignee: 'Harve Lance', - preCompletionNotes: 'pre completion notes', - dueDate: '02/14/2024', - }; - - const props = { - show: true, - eventId: 'event1', - orgId: '123', - handleClose: jest.fn(), - }; - - test('The modal should be rendered properly', async () => { - render( - - - - - - - - - - - , - ); - - await waitFor(() => - expect(screen.queryByTestId('modal-title')).toBeInTheDocument(), - ); - - await waitFor(() => { - return expect( - screen.findByTestId('createEventActionItemBtn'), - ).resolves.toBeInTheDocument(); - }); - }); - - test('render error component on unsuccessful action item category list query', async () => { - const { queryByText } = render( - - - - - - - - - , - ); - - await wait(); - - await waitFor(() => { - expect(queryByText('createEventActionItemBtn')).not.toBeInTheDocument(); - }); - }); - - test('render error component on unsuccessful member list query', async () => { - const { queryByText } = render( - - - - - - - - - , - ); - - await wait(); - - await waitFor(() => { - expect(queryByText('createEventActionItemBtn')).not.toBeInTheDocument(); - }); - }); - - test('render error component on unsuccessful action items list query', async () => { - const { queryByText } = render( - - - - - - - - - , - ); - - await wait(); - - await waitFor(() => { - expect(queryByText('createEventActionItemBtn')).not.toBeInTheDocument(); - }); - }); - - test('creates new action item associated with the event', async () => { - render( - - - - - - - - - - - , - ); - - await wait(); - - await waitFor(() => { - expect( - screen.getByTestId('createEventActionItemBtn'), - ).toBeInTheDocument(); - }); - userEvent.click(screen.getByTestId('createEventActionItemBtn')); - - await waitFor(() => { - return expect( - screen.findByTestId('createActionItemModalCloseBtn'), - ).resolves.toBeInTheDocument(); - }); - - await waitFor(() => { - expect( - screen.getByTestId('formSelectActionItemCategory'), - ).toBeInTheDocument(); - }); - - userEvent.selectOptions( - screen.getByTestId('formSelectActionItemCategory'), - formData.actionItemCategory, - ); - - userEvent.selectOptions( - screen.getByTestId('formSelectAssignee'), - formData.assignee, - ); - - userEvent.type( - screen.getByPlaceholderText(translations.preCompletionNotes), - formData.preCompletionNotes, - ); - - const dueDatePicker = screen.getByLabelText(translations.dueDate); - fireEvent.change(dueDatePicker, { - target: { value: formData.dueDate }, - }); - - userEvent.click(screen.getByTestId('createActionItemFormSubmitBtn')); - - await waitFor(() => { - expect(toast.success).toBeCalledWith(translations.successfulCreation); - }); - }); - - test('toasts error on unsuccessful creation', async () => { - render( - - - - - - - - - - - , - ); - - await wait(); - - await waitFor(() => { - expect( - screen.getByTestId('createEventActionItemBtn'), - ).toBeInTheDocument(); - }); - userEvent.click(screen.getByTestId('createEventActionItemBtn')); - - await waitFor(() => { - return expect( - screen.findByTestId('createActionItemModalCloseBtn'), - ).resolves.toBeInTheDocument(); - }); - - await waitFor(() => { - expect( - screen.getByTestId('formSelectActionItemCategory'), - ).toBeInTheDocument(); - }); - - userEvent.selectOptions( - screen.getByTestId('formSelectActionItemCategory'), - formData.actionItemCategory, - ); - - userEvent.selectOptions( - screen.getByTestId('formSelectAssignee'), - formData.assignee, - ); - - userEvent.type( - screen.getByPlaceholderText(translations.preCompletionNotes), - formData.preCompletionNotes, - ); - - const dueDatePicker = screen.getByLabelText(translations.dueDate); - fireEvent.change(dueDatePicker, { - target: { value: formData.dueDate }, - }); - - userEvent.click(screen.getByTestId('createActionItemFormSubmitBtn')); - - await waitFor(() => { - expect(toast.error).toHaveBeenCalled(); - }); - }); -}); diff --git a/src/components/ActionItems/ActionItemsModal.tsx b/src/components/ActionItems/ActionItemsModal.tsx deleted file mode 100644 index 8b8cafba4a..0000000000 --- a/src/components/ActionItems/ActionItemsModal.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import React from 'react'; -import { Modal } from 'react-bootstrap'; -import styles from 'components/ActionItems/ActionItemsWrapper.module.css'; -import { ActionItemsModalBody } from './ActionItemsModalBody'; -import { useTranslation } from 'react-i18next'; - -export interface InterfaceModalProp { - show: boolean; - eventId: string; - orgId: string; - handleClose: () => void; -} - -export const ActionItemsModal = (props: InterfaceModalProp): JSX.Element => { - const { t } = useTranslation('translation', { - keyPrefix: 'organizationActionItems', - }); - - return ( - <> - - - - {t('eventActionItems')} - - - - - - - - ); -}; diff --git a/src/components/ActionItems/ActionItemsModalBody.tsx b/src/components/ActionItems/ActionItemsModalBody.tsx deleted file mode 100644 index 1aeb536b8b..0000000000 --- a/src/components/ActionItems/ActionItemsModalBody.tsx +++ /dev/null @@ -1,218 +0,0 @@ -import React, { useState } from 'react'; -import type { ChangeEvent } from 'react'; -import { Button } from 'react-bootstrap'; -import { useMutation, useQuery } from '@apollo/client'; -import { - ACTION_ITEM_CATEGORY_LIST, - ACTION_ITEM_LIST, - MEMBERS_LIST, -} from 'GraphQl/Queries/Queries'; -import styles from 'components/ActionItems/ActionItemsWrapper.module.css'; -import type { - InterfaceActionItemCategoryList, - InterfaceActionItemList, - InterfaceMembersList, -} from 'utils/interfaces'; - -import ActionItemsContainer from 'components/ActionItems/ActionItemsContainer'; -import Loader from 'components/Loader/Loader'; -import { WarningAmberRounded } from '@mui/icons-material'; -import { CREATE_ACTION_ITEM_MUTATION } from 'GraphQl/Mutations/ActionItemMutations'; -import dayjs from 'dayjs'; -import { toast } from 'react-toastify'; -import ActionItemCreateModal from 'screens/OrganizationActionItems/ActionItemCreateModal'; -import { useTranslation } from 'react-i18next'; - -export const ActionItemsModalBody = ({ - organizationId, - eventId, -}: { - organizationId: string; - eventId: string; -}): JSX.Element => { - const { t } = useTranslation('translation', { - keyPrefix: 'organizationActionItems', - }); - const { t: tCommon } = useTranslation('common'); - - const [dueDate, setDueDate] = useState(new Date()); - const [actionItemCreateModalIsOpen, setActionItemCreateModalIsOpen] = - useState(false); - - const [formState, setFormState] = useState({ - actionItemCategoryId: '', - assigneeId: '', - preCompletionNotes: '', - }); - - const { - data: actionItemCategoriesData, - loading: actionItemCategoriesLoading, - error: actionItemCategoriesError, - }: { - data: InterfaceActionItemCategoryList | undefined; - loading: boolean; - error?: Error | undefined; - } = useQuery(ACTION_ITEM_CATEGORY_LIST, { - variables: { - organizationId, - }, - notifyOnNetworkStatusChange: true, - }); - - const { - data: membersData, - loading: membersLoading, - error: membersError, - }: { - data: InterfaceMembersList | undefined; - loading: boolean; - error?: Error | undefined; - } = useQuery(MEMBERS_LIST, { - variables: { id: organizationId }, - }); - - const { - data: actionItemsData, - loading: actionItemsLoading, - error: actionItemsError, - refetch: actionItemsRefetch, - }: { - data: InterfaceActionItemList | undefined; - loading: boolean; - error?: Error | undefined; - refetch: () => void; - } = useQuery(ACTION_ITEM_LIST, { - variables: { - organizationId, - eventId, - orderBy: 'createdAt_DESC', - }, - notifyOnNetworkStatusChange: true, - }); - - const [createActionItem] = useMutation(CREATE_ACTION_ITEM_MUTATION); - - const createActionItemHandler = async ( - e: ChangeEvent, - ): Promise => { - e.preventDefault(); - try { - await createActionItem({ - variables: { - assigneeId: formState.assigneeId, - actionItemCategoryId: formState.actionItemCategoryId, - eventId, - preCompletionNotes: formState.preCompletionNotes, - dueDate: dayjs(dueDate).format('YYYY-MM-DD'), - }, - }); - - setFormState({ - assigneeId: '', - actionItemCategoryId: '', - preCompletionNotes: '', - }); - - setDueDate(new Date()); - - actionItemsRefetch(); - hideCreateModal(); - toast.success(t('successfulCreation')); - } catch (error: unknown) { - if (error instanceof Error) { - toast.error(error.message); - console.log(error.message); - } - } - }; - - const showCreateModal = (): void => { - setActionItemCreateModalIsOpen(!actionItemCreateModalIsOpen); - }; - - const hideCreateModal = (): void => { - setActionItemCreateModalIsOpen(!actionItemCreateModalIsOpen); - }; - - if (actionItemCategoriesLoading || membersLoading || actionItemsLoading) { - return ; - } - - if (actionItemCategoriesError || membersError || actionItemsError) { - return ( -
- -
- Error occured while loading{' '} - {actionItemCategoriesError - ? 'Action Item Categories' - : membersError - ? 'Members List' - : 'Action Items List'}{' '} - Data -
- {actionItemCategoriesError - ? actionItemCategoriesError.message - : membersError - ? membersError.message - : actionItemsError?.message} -
-
- ); - } - - const actionItemCategories = - actionItemCategoriesData?.actionItemCategoriesByOrganization.filter( - (category) => !category.isDisabled, - ); - - const completedActionItemsCount = - actionItemsData?.actionItemsByOrganization.reduce( - (acc, item) => (item.isCompleted === true ? acc + 1 : acc), - 0, - ); - - return ( - <> -
- - Status: - {actionItemsData?.actionItemsByOrganization.length} action items - assigned, {completedActionItemsCount} completed - - - -
- - - - {/* Create Modal */} - - - ); -}; diff --git a/src/components/ActionItems/ActionItemsWrapper.module.css b/src/components/ActionItems/ActionItemsWrapper.module.css deleted file mode 100644 index 125db8a125..0000000000 --- a/src/components/ActionItems/ActionItemsWrapper.module.css +++ /dev/null @@ -1,53 +0,0 @@ -.actionItemsModal { - margin: auto; - max-width: 85%; -} - -button .iconWrapper { - width: 32px; - padding-right: 4px; - margin-right: 4px; -} - -button .iconWrapperSm { - width: 32px; - display: flex; - justify-content: center; - align-items: center; -} - -.errorIcon { - transform: scale(1.5); - color: var(--bs-danger); - margin-bottom: 1rem; -} - -.greenregbtn { - margin: 1rem 0 0; - margin-top: 0; - margin-right: 4px; - border: 1px solid var(--bs-gray-300); - box-shadow: 0 2px 2px var(--bs-gray-300); - padding: 10px 10px; - border-radius: 5px; - background-color: var(--bs-primary); - width: 100%; - font-size: 16px; - color: var(--bs-white); - outline: none; - font-weight: 600; - cursor: pointer; - transition: - transform 0.2s, - box-shadow 0.2s; - max-width: 100px; -} - -.message { - margin-top: 15%; - margin-bottom: 15%; - display: flex; - justify-content: center; - align-items: center; - flex-direction: column; -} diff --git a/src/components/ActionItems/ActionItemsWrapper.test.tsx b/src/components/ActionItems/ActionItemsWrapper.test.tsx deleted file mode 100644 index 7b27e7ccd3..0000000000 --- a/src/components/ActionItems/ActionItemsWrapper.test.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import React from 'react'; -import { act, render, screen, waitFor } from '@testing-library/react'; -import { MockedProvider } from '@apollo/react-testing'; -import { ActionItemsWrapper } from './ActionItemsWrapper'; -import { BrowserRouter } from 'react-router-dom'; -import { Provider } from 'react-redux'; -import { store } from 'state/store'; -import { I18nextProvider } from 'react-i18next'; -import i18nForTest from 'utils/i18nForTest'; -import { ToastContainer } from 'react-toastify'; -import { LocalizationProvider } from '@mui/x-date-pickers'; -import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; -import { StaticMockLink } from 'utils/StaticMockLink'; -import userEvent from '@testing-library/user-event'; -import { MOCKS } from '../../screens/OrganizationActionItems/OrganizationActionItemMocks'; - -async function wait(ms = 100): Promise { - await act(() => { - return new Promise((resolve) => { - setTimeout(resolve, ms); - }); - }); -} - -const link = new StaticMockLink(MOCKS, true); - -describe('Testing Action Items Wrapper', () => { - const props = { - eventId: 'event1', - orgId: '123', - }; - - test('The button to open and close the modal should work properly', async () => { - render( - - - - - - - - - - - - , - ); - - await wait(); - - await waitFor(() => { - expect( - screen.getByLabelText('eventDashboardActionItems'), - ).toBeInTheDocument(); - }); - - userEvent.click(screen.getByLabelText('eventDashboardActionItems')); - - await waitFor(() => - expect(screen.queryByTestId('modal-title')).toBeInTheDocument(), - ); - - await waitFor(() => { - expect(screen.getByLabelText('Close')).toBeInTheDocument(); - }); - - userEvent.click(screen.getByLabelText('Close')); - - await waitFor(() => - expect(screen.queryByTestId('modal-title')).not.toBeInTheDocument(), - ); - }); -}); diff --git a/src/components/ActionItems/ActionItemsWrapper.tsx b/src/components/ActionItems/ActionItemsWrapper.tsx deleted file mode 100644 index b44e0782b2..0000000000 --- a/src/components/ActionItems/ActionItemsWrapper.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import React, { useState } from 'react'; -import { ActionItemsModal } from './ActionItemsModal'; -import { Button } from 'react-bootstrap'; -import IconComponent from 'components/IconComponent/IconComponent'; -import styles from './ActionItemsWrapper.module.css'; -import { useTranslation } from 'react-i18next'; - -type PropType = { - orgId: string; - eventId: string; -}; - -export const ActionItemsWrapper = (props: PropType): JSX.Element => { - const { t } = useTranslation('translation', { - keyPrefix: 'organizationActionItems', - }); - - const [showModal, setShowModal] = useState(false); - - return ( - <> - - {showModal && ( - setShowModal(false)} - orgId={props.orgId} - eventId={props.eventId} - /> - )} - - ); -}; diff --git a/src/components/AddOn/AddOn.test.tsx b/src/components/AddOn/AddOn.test.tsx index 8313fefcb1..68475e8196 100644 --- a/src/components/AddOn/AddOn.test.tsx +++ b/src/components/AddOn/AddOn.test.tsx @@ -15,6 +15,14 @@ describe('Testing Addon component', () => { children: 'This is a dummy text', }; + test('should render with default props', () => { + const { getByTestId } = render(); + const container = getByTestId('pluginContainer'); + expect(container).toBeInTheDocument(); + expect(container).toHaveClass('plugin-container'); + expect(container).toHaveTextContent('Default text'); + }); + test('should render props and text elements test for the page component', () => { const { getByTestId, getByText } = render( diff --git a/src/components/AddOn/AddOn.tsx b/src/components/AddOn/AddOn.tsx index 4e73c52b7c..850cc05ee4 100644 --- a/src/components/AddOn/AddOn.tsx +++ b/src/components/AddOn/AddOn.tsx @@ -2,35 +2,43 @@ import React from 'react'; import PropTypes from 'prop-types'; interface InterfaceAddOnProps { - extras: any; - name: string; - children: any; + extras?: any; + name?: string; + children?: React.ReactNode; } -// Validate Extras -function addOn({ children }: InterfaceAddOnProps): JSX.Element { +/** + * The AddOn component is used to wrap children within a plugin container. + * It also accepts additional properties (`extras` and `name`) to allow for + * extensibility and custom naming. + * + * @param props - The props for the AddOn component. + * @param extras - Additional properties for the AddOn component. + * @param name - The name for the AddOn component. + * @param children - The child elements to be rendered within the AddOn component. + * + * @returns The JSX element representing the AddOn component. + */ +function AddOn({ + children = 'Default text', + extras = {}, + name = '', +}: InterfaceAddOnProps): JSX.Element { return ( - <> -
- {children} -
- +
+ {children} +
); } -addOn.defaultProps = { - extras: {}, - name: '', - children: null, -}; - -addOn.propTypes = { +// PropTypes validation for the AddOn component +AddOn.propTypes = { extras: PropTypes.shape({ components: PropTypes.shape({}), actions: PropTypes.shape({}), }), name: PropTypes.string, - children: PropTypes.any, + children: PropTypes.node, }; -export default addOn; +export default AddOn; diff --git a/src/components/AddOn/core/AddOnEntry/AddOnEntry.test.tsx b/src/components/AddOn/core/AddOnEntry/AddOnEntry.test.tsx index c09840a8f0..3d800eb59f 100644 --- a/src/components/AddOn/core/AddOnEntry/AddOnEntry.test.tsx +++ b/src/components/AddOn/core/AddOnEntry/AddOnEntry.test.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { render } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import { BrowserRouter } from 'react-router-dom'; import AddOnEntry from './AddOnEntry'; import { @@ -76,6 +76,32 @@ describe('Testing AddOnEntry', () => { expect(getByTestId('AddOnEntry')).toBeInTheDocument(); }); + test('uses default values for title and description when not provided', () => { + // Render the component with only required parameters + const mockGetInstalledPlugins = jest.fn(); + render( + + + + + + + + + , + ); + + const titleElement = screen.getByText('No title provided'); // This will check for the default empty string in the title + const descriptionElement = screen.getByText('Description not available'); // This will check for the default empty string in the description + expect(titleElement).toBeInTheDocument(); // Ensure the title element with default value exists + expect(descriptionElement).toBeInTheDocument(); // Ensure the description element with default value exists + }); + it('renders correctly', () => { const props = { id: '1', @@ -110,6 +136,7 @@ describe('Testing AddOnEntry', () => { expect(getByText('Test addon description')).toBeInTheDocument(); expect(getByText('Test User')).toBeInTheDocument(); }); + it('Uninstall Button works correctly', async () => { const props = { id: '1', diff --git a/src/components/AddOn/core/AddOnEntry/AddOnEntry.tsx b/src/components/AddOn/core/AddOnEntry/AddOnEntry.tsx index 6f2cdaf1dc..257917e2c2 100644 --- a/src/components/AddOn/core/AddOnEntry/AddOnEntry.tsx +++ b/src/components/AddOn/core/AddOnEntry/AddOnEntry.tsx @@ -1,5 +1,4 @@ import React, { useState } from 'react'; -import PropTypes from 'prop-types'; import styles from './AddOnEntry.module.css'; import { Button, Card, Spinner } from 'react-bootstrap'; import { UPDATE_INSTALL_STATUS_PLUGIN_MUTATION } from 'GraphQl/Mutations/mutations'; @@ -8,41 +7,78 @@ import { useTranslation } from 'react-i18next'; import { toast } from 'react-toastify'; import { Navigate, useParams } from 'react-router-dom'; +/** + * Props for the `addOnEntry` component. + */ interface InterfaceAddOnEntryProps { id: string; - enabled: boolean; - title: string; - description: string; + enabled?: boolean; // Optional props + title?: string; // Optional props + description?: string; // Optional props createdBy: string; - component: string; - modified: any; + component?: string; // Optional props + modified?: any; // Optional props uninstalledOrgs: string[]; getInstalledPlugins: () => any; } +/** + * A React component that represents an add-on entry, displaying its details and allowing installation or uninstallation. + * + * @param props - The properties for the component. + * @returns A JSX element containing the add-on entry. + * + * @example + * ```tsx + * {}} + * /> + * ``` + */ function addOnEntry({ id, - title, - description, + title = 'No title provided', // Default parameter + description = 'Description not available', // Default parameter createdBy, uninstalledOrgs, getInstalledPlugins, + // enabled = false, // Default parameter + // component = '', // Default parameter + // modified = null, // Default parameter }: InterfaceAddOnEntryProps): JSX.Element { + // Translation hook with namespace 'addOnEntry' const { t } = useTranslation('translation', { keyPrefix: 'addOnEntry' }); - //getting orgId from URL + + // Getting orgId from URL parameters const { orgId: currentOrg } = useParams(); if (!currentOrg) { + // If orgId is not present in the URL, navigate to the org list page return ; } + + // State to manage button loading state const [buttonLoading, setButtonLoading] = useState(false); + // State to manage local installation status of the add-on const [isInstalledLocal, setIsInstalledLocal] = useState( uninstalledOrgs.includes(currentOrg), ); - // const [addOrgAsUninstalled] = useMutation(UPDATE_ORG_STATUS_PLUGIN_MUTATION); + + // Mutation hook for updating the install status of the plugin const [addOrgAsUninstalled] = useMutation( UPDATE_INSTALL_STATUS_PLUGIN_MUTATION, ); + /** + * Function to toggle the installation status of the plugin. + */ const togglePluginInstall = async (): Promise => { setButtonLoading(true); await addOrgAsUninstalled({ @@ -52,8 +88,11 @@ function addOnEntry({ }, }); + // Toggle the local installation status setIsInstalledLocal(!isInstalledLocal); setButtonLoading(false); + + // Display a success message based on the new installation status const dialog: string = isInstalledLocal ? t('installMsg') : t('uninstallMsg'); @@ -110,20 +149,4 @@ function addOnEntry({ ); } -addOnEntry.defaultProps = { - enabled: false, - configurable: true, - title: '', - description: '', - isInstalled: false, -}; - -addOnEntry.propTypes = { - enabled: PropTypes.bool, - configurable: PropTypes.bool, - title: PropTypes.string, - description: PropTypes.string, - isInstalled: PropTypes.bool, -}; - export default addOnEntry; diff --git a/src/components/AddOn/core/AddOnRegister/AddOnRegister.test.tsx b/src/components/AddOn/core/AddOnRegister/AddOnRegister.test.tsx index dcd749ba41..b04b450977 100644 --- a/src/components/AddOn/core/AddOnRegister/AddOnRegister.test.tsx +++ b/src/components/AddOn/core/AddOnRegister/AddOnRegister.test.tsx @@ -1,5 +1,5 @@ -import React from 'react'; -import { act, render, screen, waitFor } from '@testing-library/react'; +import React, { act } from 'react'; +import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { MockedProvider } from '@apollo/react-testing'; import { ADD_PLUGIN_MUTATION } from 'GraphQl/Mutations/mutations'; @@ -41,7 +41,7 @@ const mocks = [ query: ADD_PLUGIN_MUTATION, variables: { pluginName: 'Test Plugin', - pluginCreatedBy: 'Test Creator', + pluginCreatedBy: 'AdminTest Creator', pluginDesc: 'Test Description', pluginInstallStatus: false, installedOrgs: ['id'], @@ -52,7 +52,7 @@ const mocks = [ createPlugin: { _id: '1', pluginName: 'Test Plugin', - pluginCreatedBy: 'Test Creator', + pluginCreatedBy: 'AdminTest Creator', pluginDesc: 'Test Description', }, }, @@ -100,26 +100,31 @@ describe('Testing AddOnRegister', () => { - {} + , ); - - await wait(100); - - userEvent.click(screen.getByRole('button', { name: /Add New/i })); - userEvent.type(screen.getByPlaceholderText(/Ex: Donations/i), 'myplugin'); - userEvent.type( - screen.getByPlaceholderText(/This Plugin enables UI for/i), - 'test description', - ); - userEvent.type( - screen.getByPlaceholderText(/Ex: john Doe/i), - 'test creator', - ); }); + // Wait for the button to be in the document + await waitFor(() => + expect( + screen.getByRole('button', { name: /Add New/i }), + ).toBeInTheDocument(), + ); + + // Simulate user interactions + userEvent.click(screen.getByRole('button', { name: /Add New/i })); + userEvent.type(screen.getByPlaceholderText(/Ex: Donations/i), 'myplugin'); + userEvent.type( + screen.getByPlaceholderText(/This Plugin enables UI for/i), + 'test description', + ); + userEvent.type( + screen.getByPlaceholderText(/Ex: john Doe/i), + 'test creator', + ); }); test('Expect toast.success to be called on successful plugin addition', async () => { @@ -135,22 +140,22 @@ describe('Testing AddOnRegister', () => {
, ); - await waitFor(() => new Promise((resolve) => setTimeout(resolve, 0))); - - userEvent.click(screen.getByRole('button', { name: /Add New/i })); - await wait(100); - expect(screen.getByTestId('addonregisterBtn')).toBeInTheDocument(); - userEvent.type(screen.getByTestId('pluginName'), pluginData.pluginName); - userEvent.type( - screen.getByTestId('pluginCreatedBy'), - pluginData.pluginCreatedBy, - ); - userEvent.type(screen.getByTestId('pluginDesc'), pluginData.pluginDesc); - userEvent.click(screen.getByTestId('addonregisterBtn')); - - await wait(100); - expect(toast.success).toBeCalledWith('Plugin Added Successfully'); }); + await waitFor(() => new Promise((resolve) => setTimeout(resolve, 0))); + + userEvent.click(screen.getByRole('button', { name: /Add New/i })); + await wait(100); + expect(screen.getByTestId('addonregisterBtn')).toBeInTheDocument(); + userEvent.type(screen.getByTestId('pluginName'), pluginData.pluginName); + userEvent.type( + screen.getByTestId('pluginCreatedBy'), + pluginData.pluginCreatedBy, + ); + userEvent.type(screen.getByTestId('pluginDesc'), pluginData.pluginDesc); + userEvent.click(screen.getByTestId('addonregisterBtn')); + + await wait(100); + expect(toast.success).toBeCalledWith('Plugin added Successfully'); }); test('Expect the window to reload after successful plugin addition', async () => { @@ -166,23 +171,24 @@ describe('Testing AddOnRegister', () => { , ); - await waitFor(() => new Promise((resolve) => setTimeout(resolve, 0))); - - userEvent.click(screen.getByRole('button', { name: /Add New/i })); - await wait(100); - expect(screen.getByTestId('addonregisterBtn')).toBeInTheDocument(); - userEvent.type(screen.getByTestId('pluginName'), pluginData.pluginName); - userEvent.type( - screen.getByTestId('pluginCreatedBy'), - pluginData.pluginCreatedBy, - ); - userEvent.type(screen.getByTestId('pluginDesc'), pluginData.pluginDesc); - userEvent.click(screen.getByTestId('addonregisterBtn')); - - await wait(3000); // Waiting for 3 seconds to reload the page as timeout is set to 2 seconds in the component - expect(mockNavigate).toHaveBeenCalledWith(0); }); + await waitFor(() => new Promise((resolve) => setTimeout(resolve, 0))); + + userEvent.click(screen.getByRole('button', { name: /Add New/i })); + await wait(100); + expect(screen.getByTestId('addonregisterBtn')).toBeInTheDocument(); + userEvent.type(screen.getByTestId('pluginName'), pluginData.pluginName); + userEvent.type( + screen.getByTestId('pluginCreatedBy'), + pluginData.pluginCreatedBy, + ); + userEvent.type(screen.getByTestId('pluginDesc'), pluginData.pluginDesc); + userEvent.click(screen.getByTestId('addonregisterBtn')); + + await wait(3000); // Waiting for 3 seconds to reload the page as timeout is set to 2 seconds in the component + expect(mockNavigate).toHaveBeenCalledWith(0); }); + test('should be redirected to /orglist if orgId is undefined', async () => { mockId = undefined; render( @@ -190,7 +196,7 @@ describe('Testing AddOnRegister', () => { - {} + diff --git a/src/components/AddOn/core/AddOnRegister/AddOnRegister.tsx b/src/components/AddOn/core/AddOnRegister/AddOnRegister.tsx index 9f88775265..56ed6006c2 100644 --- a/src/components/AddOn/core/AddOnRegister/AddOnRegister.tsx +++ b/src/components/AddOn/core/AddOnRegister/AddOnRegister.tsx @@ -8,6 +8,9 @@ import { useTranslation } from 'react-i18next'; import { toast } from 'react-toastify'; import { Navigate, useNavigate, useParams } from 'react-router-dom'; +/** + * Interface defining the form state for the `addOnRegister` component. + */ interface InterfaceFormStateTypes { pluginName: string; pluginCreatedBy: string; @@ -16,30 +19,62 @@ interface InterfaceFormStateTypes { installedOrgs: [string] | []; } -function addOnRegister(): JSX.Element { +interface AddOnRegisterProps { + createdBy?: string; +} + +/** + * A React component for registering a new add-on plugin. + * + * This component: + * - Displays a button to open a modal for plugin registration. + * - Contains a form in the modal for entering plugin details. + * - Uses GraphQL mutation to register the plugin. + * - Uses `react-i18next` for localization and `react-toastify` for notifications. + * - Redirects to the organization list page if no `orgId` is found in the URL. + * + * @returns A JSX element containing the button and modal for plugin registration. + */ +function addOnRegister({ + createdBy = 'Admin', +}: AddOnRegisterProps): JSX.Element { + // Translation hook for the 'addOnRegister' namespace const { t } = useTranslation('translation', { keyPrefix: 'addOnRegister' }); + // Translation hook for the 'common' namespace const { t: tCommon } = useTranslation('common'); + // Get the organization ID from the URL parameters const { orgId: currentUrl } = useParams(); const navigate = useNavigate(); + + // Redirect to the organization list if no organization ID is found if (!currentUrl) { return ; } + // State to manage the visibility of the modal const [show, setShow] = useState(false); + // Functions to show and hide the modal const handleClose = (): void => setShow(false); const handleShow = (): void => setShow(true); + + // GraphQL mutation hook for adding a plugin const [create] = useMutation(ADD_PLUGIN_MUTATION); + // Initial form state const [formState, setFormState] = useState({ pluginName: '', - pluginCreatedBy: '', + pluginCreatedBy: createdBy, // Using the default value here pluginDesc: '', pluginInstallStatus: false, installedOrgs: [currentUrl], }); + /** + * Handles the registration of the plugin. + * Sends the form data to the GraphQL mutation and displays a success message. + */ const handleRegister = async (): Promise => { const { data } = await create({ variables: { @@ -52,14 +87,18 @@ function addOnRegister(): JSX.Element { }); if (data) { - toast.success('Plugin Added Successfully'); + // Show a success message when the plugin is added + toast.success(tCommon('addedSuccessfully', { item: 'Plugin' }) as string); + // Refresh the page after 2 seconds setTimeout(() => { navigate(0); }, 2000); } }; + return ( <> + {/* Button to open the modal */} + {/* Button to register the plugin */} + * + */ function action(props: InterfaceActionProps): JSX.Element { const actionRef = useRef(null); diff --git a/src/components/AddOn/support/components/MainContent/MainContent.tsx b/src/components/AddOn/support/components/MainContent/MainContent.tsx index 7ca4dfc8c4..eddc1b993d 100644 --- a/src/components/AddOn/support/components/MainContent/MainContent.tsx +++ b/src/components/AddOn/support/components/MainContent/MainContent.tsx @@ -1,12 +1,27 @@ import React from 'react'; import styles from './MainContent.module.css'; + +/** + * Props for the `mainContent` component. + */ interface InterfaceMainContentProps { + /** + * The child elements to be rendered inside the main content container. + */ children: any; } -// TODO: Implement extras plugins -// TODO: Implement additional styles -// id - [plugin/component-name]-main-content if is in plugin +/** + * A React component that renders a main content container with additional styles. + * + * @param props - The properties for the component. + * @returns A JSX element containing the main content container with the provided child elements. + * + * @example + * + *

Main content goes here

+ *
+ */ function mainContent({ children }: InterfaceMainContentProps): JSX.Element { return (
diff --git a/src/components/AddOn/support/components/SidePanel/SidePanel.tsx b/src/components/AddOn/support/components/SidePanel/SidePanel.tsx index 2eda5e7225..d4c0d65966 100644 --- a/src/components/AddOn/support/components/SidePanel/SidePanel.tsx +++ b/src/components/AddOn/support/components/SidePanel/SidePanel.tsx @@ -1,12 +1,32 @@ import React from 'react'; import styles from './SidePanel.module.css'; + +/** + * Props for the `sidePanel` component. + */ interface InterfaceSidePanelProps { + /** + * Whether the side panel should be collapsed. + */ collapse?: boolean; + + /** + * The child elements to be rendered inside the side panel. + */ children: any; } -// TODO: Implement Extras Plugin -// id - [plugin-name]-side-panel +/** + * A React component that renders a side panel with an optional collapse state. + * + * @param props - The properties for the component. + * @returns A JSX element containing the side panel with the provided child elements. + * + * @example + * + *

Side panel content

+ *
+ */ function sidePanel({ collapse, children, diff --git a/src/components/AddOn/support/services/Plugin.helper.ts b/src/components/AddOn/support/services/Plugin.helper.ts index 4730f0c568..1ebefc351f 100644 --- a/src/components/AddOn/support/services/Plugin.helper.ts +++ b/src/components/AddOn/support/services/Plugin.helper.ts @@ -1,14 +1,34 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/** + * Helper class for managing plugin-related tasks such as fetching store data, installed plugins, and generating plugin links. + */ class PluginHelper { + /** + * Fetches the store data from a local server. + * + * @returns A promise that resolves to the store data in JSON format. + */ fetchStore = async (): Promise => { const result = await fetch(`http://localhost:${process.env.PORT}/store`); return await result.json(); }; + /** + * Fetches the list of installed plugins from a local server. + * + * @returns A promise that resolves to the installed plugins data in JSON format. + */ fetchInstalled = async (): Promise => { const result = await fetch(`http://localhost:3005/installed`); return await result.json(); }; + /** + * Generates an array of links for the enabled plugins. + * + * @param plugins - An array of plugin objects. + * @returns An array of objects containing the name and URL of each enabled plugin. + */ generateLinks = (plugins: any[]): { name: string; url: string }[] => { return plugins .filter((plugin: any) => plugin.enabled) diff --git a/src/components/AddPeopleToTag/AddPeopleToTag.module.css b/src/components/AddPeopleToTag/AddPeopleToTag.module.css new file mode 100644 index 0000000000..fb8599d96c --- /dev/null +++ b/src/components/AddPeopleToTag/AddPeopleToTag.module.css @@ -0,0 +1,77 @@ +.errorContainer { + min-height: 100vh; +} + +.errorMessage { + margin-top: 25%; + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; +} + +.errorIcon { + transform: scale(1.5); + color: var(--bs-danger); + margin-bottom: 1rem; +} + +.tableHeader { + background-color: var(--bs-primary); + color: var(--bs-white); + font-size: 1rem; +} + +.rowBackground { + background-color: var(--bs-white); + max-height: 120px; +} + +.scrollContainer { + max-height: 100px; /* Adjust as needed */ + overflow-y: auto; + margin-bottom: 1rem; +} + +.memberBadge { + display: flex; + align-items: center; + padding: 5px 10px; + border-radius: 12px; + background-color: #f8f9fa; /* Light background */ + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + max-width: calc(100% - 30px); /* Ensure it fits within the container */ +} + +.removeFilterIcon { + cursor: pointer; +} + +.scrollContainer { + max-height: 350px; /* Set your desired max height */ + overflow-y: auto; /* Enable vertical scrolling */ +} + +/* SimpleLoader.css */ +.simple-loader { + display: flex; + justify-content: center; + align-items: center; + width: 100%; + height: 100%; +} + +.spinner { + width: 40px; + height: 40px; + border: 4px solid rgba(0, 0, 0, 0.1); + border-top-color: #3498db; + border-radius: 50%; + animation: spin 0.6s linear infinite; +} + +@keyframes spin { + to { + transform: rotate(360deg); + } +} diff --git a/src/components/AddPeopleToTag/AddPeopleToTag.test.tsx b/src/components/AddPeopleToTag/AddPeopleToTag.test.tsx new file mode 100644 index 0000000000..4b24694a25 --- /dev/null +++ b/src/components/AddPeopleToTag/AddPeopleToTag.test.tsx @@ -0,0 +1,198 @@ +import React from 'react'; +import { MockedProvider } from '@apollo/react-testing'; +import type { RenderResult } from '@testing-library/react'; +import { + render, + screen, + fireEvent, + cleanup, + waitFor, +} from '@testing-library/react'; +import { Provider } from 'react-redux'; +import { MemoryRouter, Route, Routes } from 'react-router-dom'; +import 'jest-location-mock'; +import { I18nextProvider } from 'react-i18next'; + +import { store } from 'state/store'; +import userEvent from '@testing-library/user-event'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import { toast } from 'react-toastify'; +import type { ApolloLink } from '@apollo/client'; +import type { InterfaceAddPeopleToTagProps } from './AddPeopleToTag'; +import AddPeopleToTag from './AddPeopleToTag'; +import i18n from 'utils/i18nForTest'; +import { MOCKS, MOCKS_ERROR } from './AddPeopleToTagsMocks'; + +const link = new StaticMockLink(MOCKS, true); +const link2 = new StaticMockLink(MOCKS_ERROR, true); + +async function wait(): Promise { + await waitFor(() => { + // The waitFor utility automatically uses optimal timing + return Promise.resolve(); + }); +} + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + error: jest.fn(), + }, +})); + +const translations = { + ...JSON.parse( + JSON.stringify(i18n.getDataByLanguage('en')?.translation.manageTag ?? {}), + ), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.common ?? {})), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.errors ?? {})), +}; + +const props: InterfaceAddPeopleToTagProps = { + addPeopleToTagModalIsOpen: true, + hideAddPeopleToTagModal: () => {}, + refetchAssignedMembersData: () => {}, + t: (key: string) => translations[key], + tCommon: (key: string) => translations[key], +}; + +const renderAddPeopleToTagModal = ( + props: InterfaceAddPeopleToTagProps, + link: ApolloLink, +): RenderResult => { + return render( + + + + + + } + /> + + + + + , + ); +}; + +describe('Organisation Tags Page', () => { + beforeEach(() => { + jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: 'orgId' }), + })); + // cache.reset(); + }); + + afterEach(() => { + jest.clearAllMocks(); + cleanup(); + }); + + test('Component loads correctly', async () => { + const { getByText } = renderAddPeopleToTagModal(props, link); + + await wait(); + + await waitFor(() => { + expect(getByText(translations.addPeople)).toBeInTheDocument(); + }); + }); + + test('Renders error component when when query is unsuccessful', async () => { + const { queryByText } = renderAddPeopleToTagModal(props, link2); + + await wait(); + + await waitFor(() => { + expect(queryByText(translations.addPeople)).not.toBeInTheDocument(); + }); + }); + + test('Selects and deselects members to assign to', async () => { + renderAddPeopleToTagModal(props, link); + + await wait(); + + await waitFor(() => { + expect(screen.getAllByTestId('selectMemberBtn')[0]).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('selectMemberBtn')[0]); + + await waitFor(() => { + expect(screen.getAllByTestId('selectMemberBtn')[1]).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('selectMemberBtn')[1]); + + await waitFor(() => { + expect( + screen.getAllByTestId('clearSelectedMember')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('clearSelectedMember')[0]); + + await waitFor(() => { + expect(screen.getAllByTestId('deselectMemberBtn')[0]).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('deselectMemberBtn')[0]); + }); + + test('Renders more members with infinite scroll', async () => { + const { getByText } = renderAddPeopleToTagModal(props, link); + + await wait(); + + await waitFor(() => { + expect(getByText(translations.addPeople)).toBeInTheDocument(); + }); + + // Find the infinite scroll div by test ID or another selector + const scrollableDiv = screen.getByTestId('scrollableDiv'); + + const initialMemberDataLength = screen.getAllByTestId('memberName').length; + + // Set scroll position to the bottom + fireEvent.scroll(scrollableDiv, { + target: { scrollY: scrollableDiv.scrollHeight }, + }); + + await waitFor(() => { + const finalMemberDataLength = screen.getAllByTestId('memberName').length; + expect(finalMemberDataLength).toBeGreaterThan(initialMemberDataLength); + + expect(getByText(translations.addPeople)).toBeInTheDocument(); + }); + }); + + test('Assigns tag to multiple people', async () => { + renderAddPeopleToTagModal(props, link); + + await wait(); + + await waitFor(() => { + expect(screen.getAllByTestId('selectMemberBtn')[0]).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('selectMemberBtn')[0]); + + await waitFor(() => { + expect(screen.getAllByTestId('selectMemberBtn')[1]).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('selectMemberBtn')[1]); + + await waitFor(() => { + expect(screen.getAllByTestId('selectMemberBtn')[2]).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('selectMemberBtn')[2]); + + userEvent.click(screen.getByTestId('assignPeopleBtn')); + + await waitFor(() => { + expect(toast.success).toHaveBeenCalledWith( + translations.successfullyAssignedToPeople, + ); + }); + }); +}); diff --git a/src/components/AddPeopleToTag/AddPeopleToTag.tsx b/src/components/AddPeopleToTag/AddPeopleToTag.tsx new file mode 100644 index 0000000000..a43a47b006 --- /dev/null +++ b/src/components/AddPeopleToTag/AddPeopleToTag.tsx @@ -0,0 +1,377 @@ +import type { ApolloError } from '@apollo/client'; +import { useMutation, useQuery } from '@apollo/client'; +import type { GridCellParams, GridColDef } from '@mui/x-data-grid'; +import { DataGrid } from '@mui/x-data-grid'; +import Loader from 'components/Loader/Loader'; +import { USER_TAGS_MEMBERS_TO_ASSIGN_TO } from 'GraphQl/Queries/userTagQueries'; +import type { ChangeEvent } from 'react'; +import React, { useState } from 'react'; +import { Modal, Form, Button } from 'react-bootstrap'; +import { useParams } from 'react-router-dom'; +import type { InterfaceQueryUserTagsMembersToAssignTo } from 'utils/interfaces'; +import styles from './AddPeopleToTag.module.css'; +import { + ADD_PEOPLE_TO_TAGS_QUERY_LIMIT, + dataGridStyle, +} from 'utils/organizationTagsUtils'; +import { Stack } from '@mui/material'; +import { toast } from 'react-toastify'; +import { ADD_PEOPLE_TO_TAG } from 'GraphQl/Mutations/TagMutations'; +import InfiniteScroll from 'react-infinite-scroll-component'; +import { WarningAmberRounded } from '@mui/icons-material'; +import { useTranslation } from 'react-i18next'; + +/** + * Props for the `AddPeopleToTag` component. + */ +export interface InterfaceAddPeopleToTagProps { + addPeopleToTagModalIsOpen: boolean; + hideAddPeopleToTagModal: () => void; + refetchAssignedMembersData: () => void; + t: (key: string) => string; + tCommon: (key: string) => string; +} + +interface InterfaceMemberData { + _id: string; + firstName: string; + lastName: string; +} + +const AddPeopleToTag: React.FC = ({ + addPeopleToTagModalIsOpen, + hideAddPeopleToTagModal, + refetchAssignedMembersData, + t, + tCommon, +}) => { + const { tagId: currentTagId } = useParams(); + + const { t: tErrors } = useTranslation('error'); + + const [assignToMembers, setAssignToMembers] = useState( + [], + ); + + const { + data: userTagsMembersToAssignToData, + loading: userTagsMembersToAssignToLoading, + error: userTagsMembersToAssignToError, + fetchMore: fetchMoreMembersToAssignTo, + }: { + data?: { + getUserTag: InterfaceQueryUserTagsMembersToAssignTo; + }; + loading: boolean; + error?: ApolloError; + fetchMore: (options: { + variables: { + after?: string | null; + first?: number | null; + }; + updateQuery?: ( + previousQueryResult: { + getUserTag: InterfaceQueryUserTagsMembersToAssignTo; + }, + options: { + fetchMoreResult: { + getUserTag: InterfaceQueryUserTagsMembersToAssignTo; + }; + }, + ) => { getUserTag: InterfaceQueryUserTagsMembersToAssignTo }; + }) => Promise; + } = useQuery(USER_TAGS_MEMBERS_TO_ASSIGN_TO, { + variables: { + id: currentTagId, + first: ADD_PEOPLE_TO_TAGS_QUERY_LIMIT, + }, + skip: !addPeopleToTagModalIsOpen, + }); + + const loadMoreMembersToAssignTo = (): void => { + fetchMoreMembersToAssignTo({ + variables: { + first: ADD_PEOPLE_TO_TAGS_QUERY_LIMIT, + after: + userTagsMembersToAssignToData?.getUserTag.usersToAssignTo.pageInfo + .endCursor, // Fetch after the last loaded cursor + }, + updateQuery: ( + prevResult: { getUserTag: InterfaceQueryUserTagsMembersToAssignTo }, + { + fetchMoreResult, + }: { + fetchMoreResult: { + getUserTag: InterfaceQueryUserTagsMembersToAssignTo; + }; + }, + ) => { + if (!fetchMoreResult) return prevResult; + + return { + getUserTag: { + ...fetchMoreResult.getUserTag, + usersToAssignTo: { + ...fetchMoreResult.getUserTag.usersToAssignTo, + edges: [ + ...prevResult.getUserTag.usersToAssignTo.edges, + ...fetchMoreResult.getUserTag.usersToAssignTo.edges, + ], + }, + }, + }; + }, + }); + }; + + const userTagMembersToAssignTo = + userTagsMembersToAssignToData?.getUserTag.usersToAssignTo.edges.map( + (edge) => edge.node, + ); + + const handleAddOrRemoveMember = (member: InterfaceMemberData): void => { + setAssignToMembers((prevMembers) => { + const isAssigned = prevMembers.some((m) => m._id === member._id); + if (isAssigned) { + return prevMembers.filter((m) => m._id !== member._id); + } else { + return [...prevMembers, member]; + } + }); + }; + + const removeMember = (id: string): void => { + setAssignToMembers((prevMembers) => + prevMembers.filter((m) => m._id !== id), + ); + }; + + const [addPeople, { loading: addPeopleToTagLoading }] = + useMutation(ADD_PEOPLE_TO_TAG); + + const addPeopleToCurrentTag = async ( + e: ChangeEvent, + ): Promise => { + e.preventDefault(); + + try { + const { data } = await addPeople({ + variables: { + tagId: currentTagId, + userIds: assignToMembers.map((member) => member._id), + }, + }); + + if (data) { + toast.success(t('successfullyAssignedToPeople')); + refetchAssignedMembersData(); + hideAddPeopleToTagModal(); + setAssignToMembers([]); + } + } catch (error: unknown) { + /* istanbul ignore next */ + const errorMessage = + error instanceof Error ? error.message : tErrors('unknownError'); + toast.error(errorMessage); + } + }; + + if (userTagsMembersToAssignToError) { + return ( +
+
+ +
+ {t('errorOccurredWhileLoadingMembers')} +
+ {userTagsMembersToAssignToError.message} +
+
+
+ ); + } + + const columns: GridColDef[] = [ + { + field: 'id', + headerName: '#', + minWidth: 100, + align: 'center', + headerAlign: 'center', + headerClassName: `${styles.tableHeader}`, + sortable: false, + renderCell: (params: GridCellParams) => { + return
{params.row.id}
; + }, + }, + { + field: 'userName', + headerName: t('userName'), + flex: 2, + minWidth: 100, + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + return ( +
+ {params.row.firstName + ' ' + params.row.lastName} +
+ ); + }, + }, + { + field: 'actions', + headerName: t('actions'), + flex: 1, + align: 'center', + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + const isToBeAssigned = assignToMembers.some( + (member) => member._id === params.row._id, + ); + + return ( + + ); + }, + }, + ]; + + return ( + <> + + + {t('addPeople')} + + + + {userTagsMembersToAssignToLoading ? ( + + ) : ( + <> +
+ {assignToMembers.length === 0 ? ( +
+ {t('noOneSelected')} +
+ ) : ( + assignToMembers.map((member) => ( +
+ {member.firstName} {member.lastName} + removeMember(member._id)} + data-testid="clearSelectedMember" + /> +
+ )) + )} +
+ +
+ +
+
+ } + scrollableTarget="scrollableDiv" + > + row._id} + slots={{ + noRowsOverlay: /* istanbul ignore next */ () => ( + + {t('assignedToAll')} + + ), + }} + sx={dataGridStyle} + getRowClassName={() => `${styles.rowBackground}`} + autoHeight + rowHeight={65} + rows={userTagMembersToAssignTo?.map( + (membersToAssignTo, index) => ({ + id: index + 1, + ...membersToAssignTo, + }), + )} + columns={columns} + isRowSelectable={() => false} + /> +
+
+ + )} +
+ + + + + +
+ + ); +}; + +export default AddPeopleToTag; diff --git a/src/components/AddPeopleToTag/AddPeopleToTagsMocks.ts b/src/components/AddPeopleToTag/AddPeopleToTagsMocks.ts new file mode 100644 index 0000000000..ab185bb858 --- /dev/null +++ b/src/components/AddPeopleToTag/AddPeopleToTagsMocks.ts @@ -0,0 +1,169 @@ +import { ADD_PEOPLE_TO_TAG } from 'GraphQl/Mutations/TagMutations'; +import { USER_TAGS_MEMBERS_TO_ASSIGN_TO } from 'GraphQl/Queries/userTagQueries'; + +export const MOCKS = [ + { + request: { + query: USER_TAGS_MEMBERS_TO_ASSIGN_TO, + variables: { + id: '1', + first: 7, + }, + }, + result: { + data: { + getUserTag: { + name: 'tag1', + usersToAssignTo: { + edges: [ + { + node: { + _id: '1', + firstName: 'member', + lastName: '1', + }, + cursor: '1', + }, + { + node: { + _id: '2', + firstName: 'member', + lastName: '2', + }, + cursor: '2', + }, + { + node: { + _id: '3', + firstName: 'member', + lastName: '3', + }, + cursor: '3', + }, + { + node: { + _id: '4', + firstName: 'member', + lastName: '4', + }, + cursor: '4', + }, + { + node: { + _id: '5', + firstName: 'member', + lastName: '5', + }, + cursor: '5', + }, + { + node: { + _id: '6', + firstName: 'member', + lastName: '6', + }, + cursor: '6', + }, + { + node: { + _id: '7', + firstName: 'member', + lastName: '7', + }, + cursor: '7', + }, + ], + pageInfo: { + startCursor: '1', + endCursor: '7', + hasNextPage: true, + hasPreviousPage: false, + }, + totalCount: 10, + }, + }, + }, + }, + }, + { + request: { + query: USER_TAGS_MEMBERS_TO_ASSIGN_TO, + variables: { + id: '1', + first: 7, + after: '7', + }, + }, + result: { + data: { + getUserTag: { + name: 'tag1', + usersToAssignTo: { + edges: [ + { + node: { + _id: '8', + firstName: 'member', + lastName: '8', + }, + cursor: '8', + }, + { + node: { + _id: '9', + firstName: 'member', + lastName: '9', + }, + cursor: '9', + }, + { + node: { + _id: '10', + firstName: 'member', + lastName: '10', + }, + cursor: '10', + }, + ], + pageInfo: { + startCursor: '8', + endCursor: '10', + hasNextPage: false, + hasPreviousPage: true, + }, + totalCount: 10, + }, + }, + }, + }, + }, + { + request: { + query: ADD_PEOPLE_TO_TAG, + variables: { + tagId: '1', + userIds: ['1', '3', '5'], + }, + }, + result: { + data: { + addPeopleToUserTag: { + _id: '1', + }, + }, + }, + }, +]; + +export const MOCKS_ERROR = [ + { + request: { + query: USER_TAGS_MEMBERS_TO_ASSIGN_TO, + variables: { + id: '1', + first: 7, + }, + }, + error: new Error('Mock Graphql Error'), + }, +]; diff --git a/src/components/Advertisements/Advertisements.test.tsx b/src/components/Advertisements/Advertisements.test.tsx index fcb8889dad..c0992a1012 100644 --- a/src/components/Advertisements/Advertisements.test.tsx +++ b/src/components/Advertisements/Advertisements.test.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { act } from 'react'; import { ApolloClient, ApolloLink, @@ -7,7 +7,7 @@ import { InMemoryCache, } from '@apollo/client'; import { MockedProvider } from '@apollo/client/testing'; -import { act, fireEvent, render, screen } from '@testing-library/react'; +import { fireEvent, render, screen } from '@testing-library/react'; import 'jest-location-mock'; import type { DocumentNode, NormalizedCacheObject } from '@apollo/client'; @@ -407,7 +407,7 @@ describe('Testing Advertisement Component', () => { userEvent.click(screen.getByTestId('addonregister')); expect( - await screen.findByText('Advertisement created successfully'), + await screen.findByText('Advertisement created successfully.'), ).toBeInTheDocument(); }); diff --git a/src/components/Advertisements/Advertisements.tsx b/src/components/Advertisements/Advertisements.tsx index 0b880700d9..f20c2a7d8e 100644 --- a/src/components/Advertisements/Advertisements.tsx +++ b/src/components/Advertisements/Advertisements.tsx @@ -10,13 +10,34 @@ import { useParams } from 'react-router-dom'; import type { InterfaceQueryOrganizationAdvertisementListItem } from 'utils/interfaces'; import InfiniteScroll from 'react-infinite-scroll-component'; -export default function advertisements(): JSX.Element { +/** + * The `Advertisements` component displays a list of advertisements for a specific organization. + * It uses a tab-based interface to toggle between active and archived advertisements. + * + * The component utilizes the `useQuery` hook from Apollo Client to fetch advertisements data + * and implements infinite scrolling to load more advertisements as the user scrolls. + * + * @example + * return ( + * + * ) + * + */ + +export default function Advertisements(): JSX.Element { + // Retrieve the organization ID from URL parameters const { orgId: currentOrgId } = useParams(); + // Translation hook for internationalization const { t } = useTranslation('translation', { keyPrefix: 'advertisement' }); const { t: tCommon } = useTranslation('common'); + + // Set the document title based on the translation document.title = t('title'); + + // State to manage pagination cursor for infinite scrolling const [after, setAfter] = useState(null); + // Type definition for an advertisement object type Ad = { _id: string; name: string; @@ -26,6 +47,7 @@ export default function advertisements(): JSX.Element { startDate: string; // Assuming it's a string in the format 'yyyy-MM-dd' }; + // GraphQL query to fetch the list of advertisements const { data: orgAdvertisementListData, refetch, @@ -41,24 +63,28 @@ export default function advertisements(): JSX.Element { first: 6, }, }); - const [advertisements, setAdvertisements] = useState( + + // State to manage the list of advertisements + const [advertisements, setAdvertisements] = useState( orgAdvertisementListData?.organizations[0].advertisements?.edges.map( (edge: { node: Ad }) => edge.node, ) || [], ); + // Effect hook to update advertisements list when data changes or pagination cursor changes useEffect(() => { if (orgAdvertisementListData && orgAdvertisementListData.organizations) { const ads: Ad[] = orgAdvertisementListData.organizations[0].advertisements?.edges.map( (edge) => edge.node, - ); - after - ? setAdvertisements([...advertisements, ...ads]) - : setAdvertisements(ads); + ) || []; + setAdvertisements(after ? [...advertisements, ...ads] : ads); } }, [orgAdvertisementListData, after]); + /** + * Fetches more advertisements for infinite scrolling. + */ async function loadMoreAdvertisements(): Promise { await refetch(); @@ -75,18 +101,23 @@ export default function advertisements(): JSX.Element {
+ {/* Component for registering a new advertisement */} + + {/* Tabs for active and archived advertisements */} + {/* Tab for active advertisements */} + {/* Skeleton loader while fetching more advertisements */} {[...Array(6)].map((_, index) => (
@@ -156,12 +187,15 @@ export default function advertisements(): JSX.Element { )} + + {/* Tab for archived advertisements */} + {/* Skeleton loader while fetching more advertisements */} {[...Array(6)].map((_, index) => (
@@ -237,7 +271,3 @@ export default function advertisements(): JSX.Element { ); } - -advertisements.defaultProps = {}; - -advertisements.propTypes = {}; diff --git a/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.test.tsx b/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.test.tsx index 0850d1f89f..dbd6f88cc3 100644 --- a/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.test.tsx +++ b/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.test.tsx @@ -130,7 +130,64 @@ describe('Testing Advertisement Entry Component', () => { expect(deletionFailedText).toBeNull(); }); }); + it('should use default props when none are provided', () => { + render( + , + ): void { + throw new Error('Function not implemented.'); + }} + />, + ); + + //Check if component renders with default ''(empty string) + const elements = screen.getAllByText(''); // This will return an array of matching elements + elements.forEach((element) => expect(element).toBeInTheDocument()); + + // Check that the component renders with default `mediaUrl` (empty string) + const mediaElement = screen.getByTestId('media'); + expect(mediaElement).toHaveAttribute('src', ''); + + // Check that the component renders with default `endDate` + const defaultEndDate = new Date().toDateString(); + expect(screen.getByText(`Ends on ${defaultEndDate}`)).toBeInTheDocument(); + // Check that the component renders with default `startDate` + const defaultStartDate = new Date().toDateString(); + console.log(screen.getByText); + expect(screen.getByText(`Ends on ${defaultStartDate}`)).toBeInTheDocument(); //fix text "Ends on"? + }); + it('should correctly override default props when values are provided', () => { + const mockName = 'Test Ad'; + const mockType = 'Banner'; + const mockMediaUrl = 'https://example.com/media.png'; + const mockEndDate = new Date(2025, 11, 31); + const mockStartDate = new Date(2024, 0, 1); + const mockOrganizationId = 'org123'; + + const { getByText } = render( + , + ): void { + throw new Error('Function not implemented.'); + }} + />, + ); + + // Check that the component renders with provided values + expect(getByText(mockName)).toBeInTheDocument(); + // Add more checks based on how each prop affects rendering + }); it('should open and close the dropdown when options button is clicked', () => { const { getByTestId, queryByText, getAllByText } = render( diff --git a/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.tsx b/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.tsx index cbc933a894..7368ded68e 100644 --- a/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.tsx +++ b/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.tsx @@ -12,30 +12,43 @@ import { toast } from 'react-toastify'; interface InterfaceAddOnEntryProps { id: string; - name: string; - mediaUrl: string; - type: string; - organizationId: string; - startDate: Date; - endDate: Date; + name?: string; + mediaUrl?: string; + type?: string; + organizationId?: string; + startDate?: Date; + endDate?: Date; setAfter: React.Dispatch>; } -function advertisementEntry({ + +/** + * Component for displaying an advertisement entry. + * Allows viewing, editing, and deleting of the advertisement. + * + * @param props - Component properties + * @returns The rendered component + */ +function AdvertisementEntry({ id, - name, - type, - mediaUrl, - endDate, - organizationId, - startDate, + name = '', + type = '', + mediaUrl = '', + endDate = new Date(), + organizationId = '', + startDate = new Date(), setAfter, }: InterfaceAddOnEntryProps): JSX.Element { const { t } = useTranslation('translation', { keyPrefix: 'advertisement' }); const { t: tCommon } = useTranslation('common'); + + // State for loading button const [buttonLoading, setButtonLoading] = useState(false); + // State for dropdown menu visibility const [dropdown, setDropdown] = useState(false); + // State for delete confirmation modal visibility const [showDeleteModal, setShowDeleteModal] = useState(false); + // Mutation hook for deleting an advertisement const [deleteAdById] = useMutation(DELETE_ADVERTISEMENT_BY_ID, { refetchQueries: [ { @@ -45,7 +58,15 @@ function advertisementEntry({ ], }); + /** + * Toggles the visibility of the delete confirmation modal. + */ const toggleShowDeleteModal = (): void => setShowDeleteModal((prev) => !prev); + + /** + * Handles advertisement deletion. + * Displays a success or error message based on the result. + */ const onDelete = async (): Promise => { setButtonLoading(true); try { @@ -54,9 +75,9 @@ function advertisementEntry({ id: id.toString(), }, }); - toast.error('Advertisement Deleted'); + toast.success(t('advertisementDeleted') as string); setButtonLoading(false); - setAfter(null); + setAfter?.(null); } catch (error: unknown) { if (error instanceof Error) { toast.error(error.message); @@ -64,9 +85,14 @@ function advertisementEntry({ setButtonLoading(false); } }; + + /** + * Toggles the visibility of the dropdown menu. + */ const handleOptionsClick = (): void => { setDropdown(!dropdown); }; + return ( <> @@ -183,7 +209,7 @@ function advertisementEntry({ ); } -advertisementEntry.propTypes = { +AdvertisementEntry.propTypes = { name: PropTypes.string, type: PropTypes.string, organizationId: PropTypes.string, @@ -192,12 +218,4 @@ advertisementEntry.propTypes = { startDate: PropTypes.instanceOf(Date), }; -advertisementEntry.defaultProps = { - name: '', - type: '', - organizationId: '', - mediaUrl: '', - endDate: new Date(), - startDate: new Date(), -}; -export default advertisementEntry; +export default AdvertisementEntry; diff --git a/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.module.css b/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.module.css index 75b90fd1d7..0c5678676b 100644 --- a/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.module.css +++ b/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.module.css @@ -1,4 +1,5 @@ .modalbtn { + margin-top: 1rem; display: flex !important; margin-left: auto; align-items: center; diff --git a/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.test.tsx b/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.test.tsx index a38823a97c..1bf16ec76b 100644 --- a/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.test.tsx +++ b/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.test.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { act } from 'react'; import { render, fireEvent, waitFor, screen } from '@testing-library/react'; import { @@ -147,12 +147,12 @@ describe('Testing Advertisement Register Component', () => { @@ -166,176 +166,242 @@ describe('Testing Advertisement Register Component', () => { }); test('create advertisement', async () => { + jest.useFakeTimers(); const setTimeoutSpy = jest.spyOn(global, 'setTimeout'); - const { getByText, queryByText, getByLabelText } = render( - - - - - - - - - , - ); - expect(getByText(translations.createAdvertisement)).toBeInTheDocument(); + await act(async () => { + render( + + + + + + + + + , + ); + }); - fireEvent.click(getByText(translations.createAdvertisement)); - expect(queryByText(translations.addNew)).toBeInTheDocument(); + expect( + screen.getByText(translations.createAdvertisement), + ).toBeInTheDocument(); - fireEvent.change(getByLabelText(translations.Rname), { - target: { value: 'Ad1' }, + await act(async () => { + fireEvent.click(screen.getByText(translations.createAdvertisement)); }); - expect(getByLabelText(translations.Rname)).toHaveValue('Ad1'); - const mediaFile = new File(['media content'], 'test.png', { - type: 'image/png', + expect(screen.queryByText(translations.addNew)).toBeInTheDocument(); + + await act(async () => { + fireEvent.change(screen.getByLabelText(translations.Rname), { + target: { value: 'Ad1' }, + }); + + const mediaFile = new File(['media content'], 'test.png', { + type: 'image/png', + }); + + fireEvent.change(screen.getByLabelText(translations.Rmedia), { + target: { + files: [mediaFile], + }, + }); }); - const mediaInput = getByLabelText(translations.Rmedia); - fireEvent.change(mediaInput, { - target: { - files: [mediaFile], - }, + await waitFor(() => { + expect(screen.getByTestId('mediaPreview')).toBeInTheDocument(); }); - const mediaPreview = await screen.findByTestId('mediaPreview'); - expect(mediaPreview).toBeInTheDocument(); + await act(async () => { + fireEvent.change(screen.getByLabelText(translations.Rtype), { + target: { value: 'BANNER' }, + }); - fireEvent.change(getByLabelText(translations.Rtype), { - target: { value: 'BANNER' }, - }); - expect(getByLabelText(translations.Rtype)).toHaveValue('BANNER'); + fireEvent.change(screen.getByLabelText(translations.RstartDate), { + target: { value: '2023-01-01' }, + }); - fireEvent.change(getByLabelText(translations.RstartDate), { - target: { value: '2023-01-01' }, + fireEvent.change(screen.getByLabelText(translations.RendDate), { + target: { value: '2023-02-01' }, + }); }); - expect(getByLabelText(translations.RstartDate)).toHaveValue('2023-01-01'); - fireEvent.change(getByLabelText(translations.RendDate), { - target: { value: '2023-02-01' }, + expect(screen.getByLabelText(translations.Rname)).toHaveValue('Ad1'); + expect(screen.getByLabelText(translations.Rtype)).toHaveValue('BANNER'); + expect(screen.getByLabelText(translations.RstartDate)).toHaveValue( + '2023-01-01', + ); + expect(screen.getByLabelText(translations.RendDate)).toHaveValue( + '2023-02-01', + ); + + await act(async () => { + fireEvent.click(screen.getByText(translations.register)); }); - expect(getByLabelText(translations.RendDate)).toHaveValue('2023-02-01'); await waitFor(() => { - fireEvent.click(getByText(translations.register)); + expect(toast.success).toBeCalledWith( + 'Advertisement created successfully.', + ); + expect(setTimeoutSpy).toHaveBeenCalled(); }); - expect(toast.success).toBeCalledWith('Advertisement created successfully'); - expect(setTimeoutSpy).toHaveBeenCalled(); + jest.useRealTimers(); }); test('update advertisement', async () => { + jest.useFakeTimers(); const setTimeoutSpy = jest.spyOn(global, 'setTimeout'); - const { getByText, getByLabelText } = render( - - - - - - - - - , - ); - - fireEvent.click(getByText(translations.edit)); - fireEvent.change(getByLabelText(translations.Rname), { - target: { value: 'Ad1' }, + await act(async () => { + render( + + + + + + + + + , + ); }); - expect(getByLabelText(translations.Rname)).toHaveValue('Ad1'); - const mediaFile = new File(['media content'], 'test.png', { - type: 'image/png', + await waitFor(() => { + expect(screen.getByText(translations.edit)).toBeInTheDocument(); }); - const mediaInput = getByLabelText(translations.Rmedia); - fireEvent.change(mediaInput, { - target: { - files: [mediaFile], - }, + await act(async () => { + fireEvent.click(screen.getByText(translations.edit)); }); - const mediaPreview = await screen.findByTestId('mediaPreview'); - expect(mediaPreview).toBeInTheDocument(); + await act(async () => { + fireEvent.change(screen.getByLabelText(translations.Rname), { + target: { value: 'Ad1' }, + }); - fireEvent.change(getByLabelText(translations.Rtype), { - target: { value: 'BANNER' }, + const mediaFile = new File(['media content'], 'test.png', { + type: 'image/png', + }); + + fireEvent.change(screen.getByLabelText(translations.Rmedia), { + target: { + files: [mediaFile], + }, + }); }); - expect(getByLabelText(translations.Rtype)).toHaveValue('BANNER'); - fireEvent.change(getByLabelText(translations.RstartDate), { - target: { value: '2023-01-01' }, + await waitFor(() => { + expect(screen.getByTestId('mediaPreview')).toBeInTheDocument(); }); - expect(getByLabelText(translations.RstartDate)).toHaveValue('2023-01-01'); - fireEvent.change(getByLabelText(translations.RendDate), { - target: { value: '2023-02-01' }, + await act(async () => { + fireEvent.change(screen.getByLabelText(translations.Rtype), { + target: { value: 'BANNER' }, + }); + + fireEvent.change(screen.getByLabelText(translations.RstartDate), { + target: { value: '2023-01-01' }, + }); + + fireEvent.change(screen.getByLabelText(translations.RendDate), { + target: { value: '2023-02-01' }, + }); + }); + + expect(screen.getByLabelText(translations.Rname)).toHaveValue('Ad1'); + expect(screen.getByLabelText(translations.Rtype)).toHaveValue('BANNER'); + expect(screen.getByLabelText(translations.RstartDate)).toHaveValue( + '2023-01-01', + ); + expect(screen.getByLabelText(translations.RendDate)).toHaveValue( + '2023-02-01', + ); + + await act(async () => { + fireEvent.click(screen.getByText(translations.saveChanges)); }); - expect(getByLabelText(translations.RendDate)).toHaveValue('2023-02-01'); await waitFor(() => { - fireEvent.click(getByText(translations.saveChanges)); + expect(toast.success).toBeCalledWith( + 'Advertisement created successfully.', + ); + expect(setTimeoutSpy).toHaveBeenCalled(); }); - expect(toast.success).toBeCalledWith('Advertisement created successfully'); - expect(setTimeoutSpy).toHaveBeenCalled(); + + jest.useRealTimers(); }); test('Logs error to the console and shows error toast when advertisement creation fails', async () => { + jest.useFakeTimers(); const setTimeoutSpy = jest.spyOn(global, 'setTimeout'); - const { getByText, queryByText } = render( - - - - - - - - - , - ); + const toastErrorSpy = jest.spyOn(toast, 'error'); + + await act(async () => { + render( + + + + + + + + + , + ); + }); - expect(getByText(translations.createAdvertisement)).toBeInTheDocument(); + expect( + screen.getByText(translations.createAdvertisement), + ).toBeInTheDocument(); - fireEvent.click(getByText(translations.createAdvertisement)); - expect(queryByText(translations.addNew)).toBeInTheDocument(); + await act(async () => { + fireEvent.click(screen.getByText(translations.createAdvertisement)); + }); + + expect(screen.queryByText(translations.addNew)).toBeInTheDocument(); + + await act(async () => { + fireEvent.click(screen.getByText(translations.register)); + }); await waitFor(() => { - fireEvent.click(getByText(translations.register)); + expect(toastErrorSpy).toHaveBeenCalledWith( + `An error occurred. Couldn't create advertisement`, + ); }); - expect(toast.error).toBeCalledWith( - 'An error occured, could not create new advertisement', - ); + expect(setTimeoutSpy).toHaveBeenCalled(); + jest.useRealTimers(); }); test('Throws error when the end date is less than the start date', async () => { + jest.useFakeTimers(); const setTimeoutSpy = jest.spyOn(global, 'setTimeout'); const { getByText, queryByText, getByLabelText } = render( @@ -343,12 +409,12 @@ describe('Testing Advertisement Register Component', () => { @@ -400,24 +466,26 @@ describe('Testing Advertisement Register Component', () => { fireEvent.click(getByText(translations.register)); }); expect(toast.error).toBeCalledWith( - 'End date must be greater than or equal to start date', + 'End Date should be greater than or equal to Start Date', ); expect(setTimeoutSpy).toHaveBeenCalled(); + jest.useRealTimers(); }); test('AdvertismentRegister component loads correctly in edit mode', async () => { + jest.useFakeTimers(); render( @@ -429,21 +497,23 @@ describe('Testing Advertisement Register Component', () => { await waitFor(() => { expect(screen.getByTestId('editBtn')).toBeInTheDocument(); }); + jest.useRealTimers(); }); test('Opens and closes modals on button click', async () => { + jest.useFakeTimers(); const { getByText, queryByText } = render( @@ -459,9 +529,11 @@ describe('Testing Advertisement Register Component', () => { await waitFor(() => { expect(queryByText(translations.close)).not.toBeInTheDocument(); }); + jest.useRealTimers(); }); test('Throws error when the end date is less than the start date while editing the advertisement', async () => { + jest.useFakeTimers(); const { getByText, getByLabelText, queryByText } = render( @@ -470,12 +542,12 @@ describe('Testing Advertisement Register Component', () => { { } @@ -521,24 +593,26 @@ describe('Testing Advertisement Register Component', () => { fireEvent.click(getByText(translations.saveChanges)); await waitFor(() => { expect(toast.error).toBeCalledWith( - 'End date must be greater than or equal to start date', + 'End Date should be greater than or equal to Start Date', ); }); + jest.useRealTimers(); }); test('Media preview renders correctly', async () => { + jest.useFakeTimers(); render( @@ -563,4 +637,5 @@ describe('Testing Advertisement Register Component', () => { fireEvent.click(closeButton); expect(mediaPreview).not.toBeInTheDocument(); }); + jest.useRealTimers(); }); diff --git a/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.tsx b/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.tsx index 78bfec9ead..1d5c51ce84 100644 --- a/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.tsx +++ b/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.tsx @@ -13,46 +13,70 @@ import dayjs from 'dayjs'; import convertToBase64 from 'utils/convertToBase64'; import { ORGANIZATION_ADVERTISEMENT_LIST } from 'GraphQl/Queries/Queries'; import { useParams } from 'react-router-dom'; + +/** + * Props for the `advertisementRegister` component. + */ interface InterfaceAddOnRegisterProps { - id?: string; // organizationId - createdBy?: string; // User - formStatus?: string; - idEdit?: string; - nameEdit?: string; - typeEdit?: string; - orgIdEdit?: string; - advertisementMediaEdit?: string; - endDateEdit?: Date; - startDateEdit?: Date; - setAfter: React.Dispatch>; + id?: string; // Optional organization ID + createdBy?: string; // Optional user who created the advertisement + formStatus?: string; // Determines if the form is in register or edit mode + idEdit?: string; // ID of the advertisement to edit + nameEdit?: string; // Name of the advertisement to edit + typeEdit?: string; // Type of the advertisement to edit + orgIdEdit?: string; // Organization ID associated with the advertisement + advertisementMediaEdit?: string; // Media URL of the advertisement to edit + endDateEdit?: Date; // End date of the advertisement to edit + startDateEdit?: Date; // Start date of the advertisement to edit + setAfter: React.Dispatch>; // Function to update parent state } + +/** + * State for the advertisement form. + */ interface InterfaceFormStateTypes { - name: string; - advertisementMedia: string; - type: string; - startDate: Date; - endDate: Date; - organizationId: string | undefined; + name: string; // Name of the advertisement + advertisementMedia: string; // Base64-encoded media of the advertisement + type: string; // Type of advertisement (e.g., BANNER, POPUP) + startDate: Date; // Start date of the advertisement + endDate: Date; // End date of the advertisement + organizationId: string | undefined; // Organization ID } +/** + * Component for registering or editing an advertisement. + * + * @param props - Contains form status, advertisement details, and a function to update parent state. + * @returns A JSX element that renders a form inside a modal for creating or editing an advertisement. + * + * @example + * ```tsx + * console.log(value)} + * /> + * ``` + */ function advertisementRegister({ - formStatus, + formStatus = 'register', idEdit, - nameEdit, - typeEdit, - advertisementMediaEdit, - endDateEdit, - startDateEdit, + nameEdit = '', + typeEdit = 'BANNER', + advertisementMediaEdit = '', + endDateEdit = new Date(), + startDateEdit = new Date(), setAfter, }: InterfaceAddOnRegisterProps): JSX.Element { const { t } = useTranslation('translation', { keyPrefix: 'advertisement' }); const { t: tCommon } = useTranslation('common'); + const { t: tErrors } = useTranslation('errors'); const { orgId: currentOrg } = useParams(); const [show, setShow] = useState(false); - const handleClose = (): void => setShow(false); - const handleShow = (): void => setShow(true); + const handleClose = (): void => setShow(false); // Closes the modal + const handleShow = (): void => setShow(true); // Shows the modal + const [create] = useMutation(ADD_ADVERTISEMENT_MUTATION, { refetchQueries: [ { @@ -61,6 +85,7 @@ function advertisementRegister({ }, ], }); + const [updateAdvertisement] = useMutation(UPDATE_ADVERTISEMENT_MUTATION, { refetchQueries: [ { @@ -69,8 +94,8 @@ function advertisementRegister({ }, ], }); - //getting organizationId from URL + // Initialize form state const [formState, setFormState] = useState({ name: '', advertisementMedia: '', @@ -80,7 +105,7 @@ function advertisementRegister({ organizationId: currentOrg, }); - //if set to edit set the formState by edit variables + // Set form state if editing useEffect(() => { if (formStatus === 'edit') { setFormState((prevState) => ({ @@ -102,12 +127,15 @@ function advertisementRegister({ endDateEdit, currentOrg, ]); - + /** + * Handles advertisement registration. + * Validates the date range and performs the mutation to create an advertisement. + */ const handleRegister = async (): Promise => { try { console.log('At handle register', formState); if (formState.endDate < formState.startDate) { - toast.error('End date must be greater than or equal to start date'); + toast.error(t('endDateGreaterOrEqual') as string); return; } const { data } = await create({ @@ -122,7 +150,7 @@ function advertisementRegister({ }); if (data) { - toast.success('Advertisement created successfully'); + toast.success(t('advertisementCreated') as string); setFormState({ name: '', advertisementMedia: '', @@ -135,11 +163,20 @@ function advertisementRegister({ setAfter(null); } catch (error: unknown) { if (error instanceof Error) { - toast.error('An error occured, could not create new advertisement'); + toast.error( + tErrors('errorOccurredCouldntCreate', { + entity: 'advertisement', + }) as string, + ); console.log('error occured', error.message); } } }; + + /** + * Handles advertisement update. + * Validates the date range and performs the mutation to update the advertisement. + */ const handleUpdate = async (): Promise => { try { const updatedFields: Partial = {}; @@ -155,7 +192,7 @@ function advertisementRegister({ updatedFields.type = formState.type; } if (formState.endDate < formState.startDate) { - toast.error('End date must be greater than or equal to start date'); + toast.error(t('endDateGreaterOrEqual') as string); return; } const startDateFormattedString = dayjs(formState.startDate).format( @@ -195,7 +232,9 @@ function advertisementRegister({ }); if (data) { - toast.success('Advertisement updated successfully'); + toast.success( + tCommon('updatedSuccessfully', { item: 'Advertisement' }) as string, + ); handleClose(); setAfter(null); } @@ -223,7 +262,6 @@ function advertisementRegister({ {tCommon('edit')}
)} - {formStatus === 'register' ? ( @@ -394,16 +432,6 @@ function advertisementRegister({ ); } -advertisementRegister.defaultProps = { - name: '', - advertisementMedia: '', - type: 'BANNER', - startDate: new Date(), - endDate: new Date(), - organizationId: '', - formStatus: 'register', -}; - advertisementRegister.propTypes = { name: PropTypes.string, advertisementMedia: PropTypes.string, diff --git a/src/components/AgendaCategory/AgendaCategoryContainer.tsx b/src/components/AgendaCategory/AgendaCategoryContainer.tsx index e803e77172..7b4c5cf8f4 100644 --- a/src/components/AgendaCategory/AgendaCategoryContainer.tsx +++ b/src/components/AgendaCategory/AgendaCategoryContainer.tsx @@ -12,10 +12,25 @@ import { import type { InterfaceAgendaItemCategoryInfo } from 'utils/interfaces'; import styles from './AgendaCategoryContainer.module.css'; -import AgendaCategoryDeleteModal from 'screens/OrganizationAgendaCategory/AgendaCategoryDeleteModal'; -import AgendaCategoryPreviewModal from 'screens/OrganizationAgendaCategory/AgendaCategoryPreviewModal'; -import AgendaCategoryUpdateModal from 'screens/OrganizationAgendaCategory/AgendaCategoryUpdateModal'; +import AgendaCategoryDeleteModal from 'components/OrgSettings/AgendaItemCategories/AgendaCategoryDeleteModal'; +import AgendaCategoryPreviewModal from 'components/OrgSettings/AgendaItemCategories/AgendaCategoryPreviewModal'; +import AgendaCategoryUpdateModal from 'components/OrgSettings/AgendaItemCategories/AgendaCategoryUpdateModal'; +/** + * Component for displaying and managing agenda item categories. + * + * @param props - Contains agenda category data and functions for data management. + * @returns A JSX element that renders agenda item categories with options to preview, edit, and delete. + * + * @example + * ```tsx + * + * ``` + */ function agendaCategoryContainer({ agendaCategoryConnection, agendaCategoryData, @@ -29,6 +44,8 @@ function agendaCategoryContainer({ keyPrefix: 'organizationAgendaCategory', }); const { t: tCommon } = useTranslation('common'); + + // State management for modals and form data const [ agendaCategoryPreviewModalIsOpen, setAgendaCategoryPreviewModalIsOpen, @@ -46,6 +63,11 @@ function agendaCategoryContainer({ createdBy: '', }); + /** + * Opens the preview modal and sets the state for the selected agenda category. + * + * @param agendaItemCategory - The agenda category to preview. + */ const showPreviewModal = ( agendaItemCategory: InterfaceAgendaItemCategoryInfo, ): void => { @@ -53,18 +75,30 @@ function agendaCategoryContainer({ setAgendaCategoryPreviewModalIsOpen(true); }; + /** + * Closes the preview modal. + */ const hidePreviewModal = (): void => { setAgendaCategoryPreviewModalIsOpen(false); }; + /** + * Toggles the visibility of the update modal. + */ const showUpdateModal = (): void => { setAgendaCategoryUpdateModalIsOpen(!agendaCategoryUpdateModalIsOpen); }; + /** + * Toggles the visibility of the update modal. + */ const hideUpdateModal = (): void => { setAgendaCategoryUpdateModalIsOpen(!agendaCategoryUpdateModalIsOpen); }; + /** + * Toggles the visibility of the delete modal. + */ const toggleDeleteModal = (): void => { setAgendaCategoryDeleteModalIsOpen(!agendaCategoryDeleteModalIsOpen); }; @@ -73,6 +107,11 @@ function agendaCategoryContainer({ UPDATE_AGENDA_ITEM_CATEGORY_MUTATION, ); + /** + * Handles the update of an agenda category. + * + * @param event - The form submit event. + */ const updateAgendaCategoryHandler = async ( event: ChangeEvent, ): Promise => { @@ -90,7 +129,7 @@ function agendaCategoryContainer({ agendaCategoryRefetch(); hideUpdateModal(); - toast.success(t('agendaCategoryUpdated')); + toast.success(t('agendaCategoryUpdated') as string); } catch (error: unknown) { if (error instanceof Error) { toast.error(`Agenda Category Update Failed ${error.message}`); @@ -102,6 +141,9 @@ function agendaCategoryContainer({ DELETE_AGENDA_ITEM_CATEGORY_MUTATION, ); + /** + * Handles the deletion of an agenda category. + */ const deleteAgendaCategoryHandler = async (): Promise => { try { await deleteAgendaCategory({ @@ -111,7 +153,7 @@ function agendaCategoryContainer({ }); agendaCategoryRefetch(); toggleDeleteModal(); - toast.success(t('agendaCategoryDeleted')); + toast.success(t('agendaCategoryDeleted') as string); } catch (error: unknown) { if (error instanceof Error) { toast.error(`Agenda Category Delete Failed, ${error.message}`); @@ -119,6 +161,11 @@ function agendaCategoryContainer({ } }; + /** + * Prepares the form state and shows the update modal for the selected agenda category. + * + * @param agendaItemCategory - The agenda category to edit. + */ const handleEditClick = ( agendaItemCategory: InterfaceAgendaItemCategoryInfo, ): void => { @@ -126,6 +173,11 @@ function agendaCategoryContainer({ showUpdateModal(); }; + /** + * Updates the form state with the selected agenda category's details. + * + * @param agendaItemCategory - The agenda category details. + */ const setAgendaCategoryState = ( agendaItemCategory: InterfaceAgendaItemCategoryInfo, ): void => { @@ -239,7 +291,7 @@ function agendaCategoryContainer({
- {/* Preview model */} + {/* Preview modal */} - {/* Update model */} + {/* Update modal */} - {/* Delete model */} + {/* Delete modal */} ({ + toast: { + success: jest.fn(), + error: jest.fn(), + }, +})); + +//temporarily fixes react-beautiful-dnd droppable method's depreciation error +//needs to be fixed in React 19 +jest.spyOn(console, 'error').mockImplementation((message) => { + if (message.includes('Support for defaultProps will be removed')) { + return; + } + console.error(message); +}); + +async function wait(ms = 100): Promise { + await act(async () => { + return new Promise((resolve) => setTimeout(resolve, ms)); + }); +} + +const translations = JSON.parse( + JSON.stringify(i18nForTest.getDataByLanguage('en')?.translation.agendaItems), +); + +describe('Testing Agenda Items components', () => { + const formData = { + title: 'AgendaItem 1 Edited', + description: 'AgendaItem 1 Description Edited', + }; + + test('component loads correctly with items', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.queryByText(translations.noAgendaItems), + ).not.toBeInTheDocument(); + }); + }); + + test('component loads correctly with no agenda items', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.queryByText(translations.noAgendaItems), + ).toBeInTheDocument(); + }); + }); + + test('opens and closes the update modal correctly', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.getAllByTestId('editAgendaItemModalBtn')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('editAgendaItemModalBtn')[0]); + + await waitFor(() => { + return expect( + screen.findByTestId('updateAgendaItemModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('updateAgendaItemModalCloseBtn')); + + await waitForElementToBeRemoved(() => + screen.queryByTestId('updateAgendaItemModalCloseBtn'), + ); + }); + + test('opens and closes the preview modal correctly', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.getAllByTestId('previewAgendaItemModalBtn')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('previewAgendaItemModalBtn')[0]); + + await waitFor(() => { + return expect( + screen.findByTestId('previewAgendaItemModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('previewAgendaItemModalCloseBtn')); + + await waitForElementToBeRemoved(() => + screen.queryByTestId('previewAgendaItemModalCloseBtn'), + ); + }); + + test('opens and closes the update and delete modals through the preview modal', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.getAllByTestId('previewAgendaItemModalBtn')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('previewAgendaItemModalBtn')[0]); + + await waitFor(() => { + return expect( + screen.findByTestId('previewAgendaItemModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + + await waitFor(() => { + expect( + screen.getByTestId('previewAgendaItemModalDeleteBtn'), + ).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('previewAgendaItemModalDeleteBtn')); + + await waitFor(() => { + return expect( + screen.findByTestId('deleteAgendaItemCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('deleteAgendaItemCloseBtn')); + + await waitForElementToBeRemoved(() => + screen.queryByTestId('deleteAgendaItemCloseBtn'), + ); + + await waitFor(() => { + expect( + screen.getByTestId('previewAgendaItemModalUpdateBtn'), + ).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('previewAgendaItemModalUpdateBtn')); + + await waitFor(() => { + return expect( + screen.findByTestId('updateAgendaItemModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('updateAgendaItemModalCloseBtn')); + + await waitForElementToBeRemoved(() => + screen.queryByTestId('updateAgendaItemModalCloseBtn'), + ); + }); + + test('updates an agenda Items and toasts success', async () => { + render( + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.getAllByTestId('editAgendaItemModalBtn')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('editAgendaItemModalBtn')[0]); + + const title = screen.getByPlaceholderText(translations.enterTitle); + const description = screen.getByPlaceholderText( + translations.enterDescription, + ); + + fireEvent.change(title, { target: { value: '' } }); + userEvent.type(title, formData.title); + + fireEvent.change(description, { target: { value: '' } }); + userEvent.type(description, formData.description); + + await waitFor(() => { + expect(screen.getByTestId('updateAgendaItemBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('updateAgendaItemBtn')); + + await waitFor(() => { + // expect(toast.success).toBeCalledWith(translations.agendaItemUpdated); + }); + }); + + test('toasts error on unsuccessful updation', async () => { + render( + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.getAllByTestId('editAgendaItemModalBtn')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('editAgendaItemModalBtn')[0]); + + const titleInput = screen.getByLabelText(translations.title); + const descriptionInput = screen.getByLabelText(translations.description); + fireEvent.change(titleInput, { target: { value: '' } }); + fireEvent.change(descriptionInput, { + target: { value: '' }, + }); + userEvent.type(titleInput, formData.title); + userEvent.type(descriptionInput, formData.description); + + await waitFor(() => { + expect(screen.getByTestId('updateAgendaItemBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('updateAgendaItemBtn')); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalled(); + }); + }); + + test('deletes the agenda item and toasts success', async () => { + render( + + + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.getAllByTestId('previewAgendaItemModalBtn')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('previewAgendaItemModalBtn')[0]); + + await waitFor(() => { + return expect( + screen.findByTestId('previewAgendaItemModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + + await waitFor(() => { + expect( + screen.getByTestId('previewAgendaItemModalDeleteBtn'), + ).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('previewAgendaItemModalDeleteBtn')); + + await waitFor(() => { + return expect( + screen.findByTestId('deleteAgendaItemCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('deleteAgendaItemBtn')); + + await waitFor(() => { + expect(toast.success).toBeCalledWith(translations.agendaItemDeleted); + }); + }); + + test('toasts error on unsuccessful deletion', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + screen.getAllByTestId('previewAgendaItemModalBtn')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('previewAgendaItemModalBtn')[0]); + + await waitFor(() => { + return expect( + screen.findByTestId('previewAgendaItemModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + + await waitFor(() => { + expect( + screen.getByTestId('previewAgendaItemModalDeleteBtn'), + ).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('previewAgendaItemModalDeleteBtn')); + + await waitFor(() => { + return expect( + screen.findByTestId('deleteAgendaItemCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('deleteAgendaItemBtn')); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalled(); + }); + }); + + // write test case for drag and drop line:- 172-202 +}); diff --git a/src/components/AgendaItems/AgendaItemsContainer.tsx b/src/components/AgendaItems/AgendaItemsContainer.tsx new file mode 100644 index 0000000000..4e50cb5fe8 --- /dev/null +++ b/src/components/AgendaItems/AgendaItemsContainer.tsx @@ -0,0 +1,456 @@ +import React, { useState } from 'react'; +import type { ChangeEvent } from 'react'; +import { Button, Col, Row } from 'react-bootstrap'; +import { useTranslation } from 'react-i18next'; +import { toast } from 'react-toastify'; +import { useMutation } from '@apollo/client'; +import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd'; +import type { DropResult } from 'react-beautiful-dnd'; + +import { + DELETE_AGENDA_ITEM_MUTATION, + UPDATE_AGENDA_ITEM_MUTATION, +} from 'GraphQl/Mutations/mutations'; +import type { + InterfaceAgendaItemInfo, + InterfaceAgendaItemCategoryInfo, +} from 'utils/interfaces'; +import styles from './AgendaItemsContainer.module.css'; + +import AgendaItemsPreviewModal from 'components/AgendaItems/AgendaItemsPreviewModal'; +import AgendaItemsDeleteModal from 'components/AgendaItems/AgendaItemsDeleteModal'; +import AgendaItemsUpdateModal from 'components/AgendaItems/AgendaItemsUpdateModal'; + +/** + * Component for displaying and managing agenda items. + * Supports drag-and-drop functionality, and includes modals for previewing, + * updating, and deleting agenda items. + * + * @param props - The props for the component. + * @returns JSX.Element + */ +function AgendaItemsContainer({ + agendaItemConnection, + agendaItemData, + agendaItemRefetch, + agendaItemCategories, +}: { + agendaItemConnection: 'Event'; + agendaItemData: InterfaceAgendaItemInfo[] | undefined; + agendaItemRefetch: () => void; + agendaItemCategories: InterfaceAgendaItemCategoryInfo[] | undefined; +}): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'agendaItems', + }); + const { t: tCommon } = useTranslation('common'); + + // State for modals + const [agendaItemPreviewModalIsOpen, setAgendaItemPreviewModalIsOpen] = + useState(false); + const [agendaItemUpdateModalIsOpen, setAgendaItemUpdateModalIsOpen] = + useState(false); + const [agendaItemDeleteModalIsOpen, setAgendaItemDeleteModalIsOpen] = + useState(false); + + // State for current agenda item ID and form data + const [agendaItemId, setAgendaItemId] = useState(''); + + const [formState, setFormState] = useState<{ + agendaItemCategoryIds: string[]; + agendaItemCategoryNames: string[]; + title: string; + description: string; + duration: string; + attachments: string[]; + urls: string[]; + createdBy: { + firstName: string; + lastName: string; + }; + }>({ + agendaItemCategoryIds: [], + agendaItemCategoryNames: [], + title: '', + description: '', + duration: '', + attachments: [], + urls: [], + createdBy: { + firstName: '', + lastName: '', + }, + }); + + /** + * Shows the preview modal with the details of the selected agenda item. + * @param agendaItem - The agenda item to preview. + */ + const showPreviewModal = (agendaItem: InterfaceAgendaItemInfo): void => { + setAgendaItemState(agendaItem); + setAgendaItemPreviewModalIsOpen(true); + }; + + /** + * Hides the preview modal. + */ + const hidePreviewModal = (): void => { + setAgendaItemPreviewModalIsOpen(false); + }; + + /** + * Toggles the visibility of the update modal. + */ + const showUpdateModal = (): void => { + setAgendaItemUpdateModalIsOpen(!agendaItemUpdateModalIsOpen); + }; + + /** + * Toggles the visibility of the update modal. + */ + const hideUpdateModal = (): void => { + setAgendaItemUpdateModalIsOpen(!agendaItemUpdateModalIsOpen); + }; + + /** + * Toggles the visibility of the delete modal. + */ + const toggleDeleteModal = (): void => { + setAgendaItemDeleteModalIsOpen(!agendaItemDeleteModalIsOpen); + }; + + const [updateAgendaItem] = useMutation(UPDATE_AGENDA_ITEM_MUTATION); + + /** + * Handles updating an agenda item. + * @param e - The form submission event. + */ + const updateAgendaItemHandler = async ( + e: ChangeEvent, + ): Promise => { + e.preventDefault(); + try { + await updateAgendaItem({ + variables: { + updateAgendaItemId: agendaItemId, + input: { + title: formState.title, + description: formState.description, + duration: formState.duration, + categories: formState.agendaItemCategoryIds, + attachments: formState.attachments, + urls: formState.urls, + }, + }, + }); + agendaItemRefetch(); + hideUpdateModal(); + toast.success(t('agendaItemUpdated') as string); + } catch (error) { + if (error instanceof Error) { + toast.error(`${error.message}`); + } + } + }; + + const [deleteAgendaItem] = useMutation(DELETE_AGENDA_ITEM_MUTATION); + + /** + * Handles deleting an agenda item. + */ + const deleteAgendaItemHandler = async (): Promise => { + try { + await deleteAgendaItem({ + variables: { + removeAgendaItemId: agendaItemId, + }, + }); + agendaItemRefetch(); + toggleDeleteModal(); + toast.success(t('agendaItemDeleted') as string); + } catch (error) { + if (error instanceof Error) { + toast.error(`${error.message}`); + } + } + }; + + /** + * Handles click event to show the update modal for the selected agenda item. + * @param agendaItem - The agenda item to update. + */ + const handleEditClick = (agendaItem: InterfaceAgendaItemInfo): void => { + setAgendaItemState(agendaItem); + showUpdateModal(); + }; + + /** + * Sets the state for the selected agenda item. + * @param agendaItem - The agenda item to set in the state. + */ + const setAgendaItemState = (agendaItem: InterfaceAgendaItemInfo): void => { + setFormState({ + ...formState, + agendaItemCategoryIds: agendaItem.categories.map( + (category) => category._id, + ), + agendaItemCategoryNames: agendaItem.categories.map( + (category) => category.name, + ), + title: agendaItem.title, + description: agendaItem.description, + duration: agendaItem.duration, + attachments: agendaItem.attachments, + urls: agendaItem.urls, + createdBy: { + firstName: agendaItem.createdBy.firstName, + lastName: agendaItem.createdBy.lastName, + }, + }); + setAgendaItemId(agendaItem._id); + }; + + /** + * Handles the end of a drag-and-drop operation. + * @param result - The result of the drag-and-drop operation. + */ + const onDragEnd = async (result: DropResult): Promise => { + if (!result.destination || !agendaItemData) { + return; + } + + const reorderedAgendaItems = Array.from(agendaItemData); + const [removed] = reorderedAgendaItems.splice(result.source.index, 1); + reorderedAgendaItems.splice(result.destination.index, 0, removed); + + try { + await Promise.all( + reorderedAgendaItems.map(async (item, index) => { + if (item.sequence !== index + 1) { + // Only update if the sequence has changed + await updateAgendaItem({ + variables: { + updateAgendaItemId: item._id, + input: { + sequence: index + 1, // Update sequence based on new index + }, + }, + }); + } + }), + ); + + // After updating all items, refetch data and notify success + agendaItemRefetch(); + } catch (error) { + if (error instanceof Error) { + toast.error(`${error.message}`); + } + } + }; + + return ( + <> +
+
+ + +
{t('sequence')}
+ + + {t('title')} + + + {t('category')} + + + {t('description')} + + +
{t('options')}
+ +
+
+ + + {(provided) => ( +
+ {agendaItemData && + agendaItemData.map((agendaItem, index) => ( + + {(provided, snapshot) => ( +
+ + + + + + {agendaItem.title} + + +
+ {agendaItem.categories.length > 0 ? ( + agendaItem.categories.map((category, idx) => ( + + {category.name} + {idx < agendaItem.categories.length - 1 && + ', '} + + )) + ) : ( + + No Category + + )} +
+ {' '} + + {agendaItem.description} + + +
+ + +
+ +
+
+ )} +
+ ))} + {agendaItemData?.length === 0 && ( +
+ {t('noAgendaItems')} +
+ )} +
+ )} +
+
+
+ {/* Preview modal */} + + {/* Delete modal */} + + {/* Update modal */} + + + ); +} + +export default AgendaItemsContainer; diff --git a/src/components/AgendaItems/AgendaItemsContainerMocks.ts b/src/components/AgendaItems/AgendaItemsContainerMocks.ts new file mode 100644 index 0000000000..11cd8b254e --- /dev/null +++ b/src/components/AgendaItems/AgendaItemsContainerMocks.ts @@ -0,0 +1,119 @@ +import { + UPDATE_AGENDA_ITEM_MUTATION, + DELETE_AGENDA_ITEM_MUTATION, +} from 'GraphQl/Mutations/AgendaItemMutations'; + +export const MOCKS = [ + { + request: { + query: UPDATE_AGENDA_ITEM_MUTATION, + variables: { + updateAgendaItemId: 'agendaItem1', + input: { + title: 'AgendaItem 1 Edited', + description: 'AgendaItem 1 Description Edited', + }, + }, + }, + result: { + data: { + updateAgendaItem: { + _id: 'agendaItem1', + }, + }, + }, + }, + { + request: { + query: UPDATE_AGENDA_ITEM_MUTATION, + variables: { + updateAgendaItemId: 'agendaItem1', + input: { + title: 'AgendaItem 1', + description: 'AgendaItem 1 Description', + }, + }, + }, + result: { + data: { + updateAgendaItem: { + _id: 'agendaItem1', + }, + }, + }, + }, + { + request: { + query: UPDATE_AGENDA_ITEM_MUTATION, + variables: { + updateAgendaItemId: 'agendaItem2', + input: { + title: 'AgendaItem 2 edited', + description: 'AgendaItem 2 Description', + }, + }, + }, + result: { + data: { + updateAgendaItem: { + _id: 'agendaItem2', + }, + }, + }, + }, + { + request: { + query: DELETE_AGENDA_ITEM_MUTATION, + variables: { + removeAgendaItemId: 'agendaItem1', + }, + }, + result: { + data: { + removeAgendaItem: { + _id: 'agendaItem1', + }, + }, + }, + }, + { + request: { + query: DELETE_AGENDA_ITEM_MUTATION, + variables: { + removeAgendaItemId: 'agendaItem2', + }, + }, + result: { + data: { + removeAgendaItem: { + _id: 'agendaItem2', + }, + }, + }, + }, +]; + +export const MOCKS_ERROR = [ + { + request: { + query: UPDATE_AGENDA_ITEM_MUTATION, + variables: { + updateAgendaItemId: 'agendaItem1', + input: { + title: 'AgendaItem 1 Edited', + description: 'AgendaItem 1 Description Edited', + }, + }, + }, + error: new Error('An error occurred'), + }, + { + request: { + query: DELETE_AGENDA_ITEM_MUTATION, + variables: { + removeAgendaItemId: 'agendaItem1', + }, + }, + error: new Error('An error occurred'), + }, +]; diff --git a/src/components/AgendaItems/AgendaItemsContainerProps.ts b/src/components/AgendaItems/AgendaItemsContainerProps.ts new file mode 100644 index 0000000000..d6dcf3feca --- /dev/null +++ b/src/components/AgendaItems/AgendaItemsContainerProps.ts @@ -0,0 +1,101 @@ +type AgendaItemConnectionType = 'Event'; + +export const props = { + agendaItemConnection: 'Event' as AgendaItemConnectionType, + agendaItemData: [ + { + _id: 'agendaItem1', + title: 'AgendaItem 1', + description: 'AgendaItem 1 Description', + duration: '2h', + attachments: ['attachment1'], + createdBy: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + urls: [], + users: [], + sequence: 1, + categories: [ + { + _id: 'category1', + name: 'Category 1', + }, + ], + organization: { + _id: 'org1', + name: 'Unity Foundation', + }, + relatedEvent: { + _id: 'event1', + title: 'Aerobics for Everyone', + }, + }, + { + _id: 'agendaItem2', + title: 'AgendaItem 2', + description: 'AgendaItem 2 Description', + duration: '1h', + attachments: ['attachment3'], + createdBy: { + _id: 'user1', + firstName: 'Jane', + lastName: 'Doe', + }, + urls: ['http://example.com'], + users: [ + { + _id: 'user2', + firstName: 'John', + lastName: 'Smith', + }, + ], + sequence: 2, + categories: [ + { + _id: 'category2', + name: 'Category 2', + }, + ], + organization: { + _id: 'org2', + name: 'Health Organization', + }, + relatedEvent: { + _id: 'event2', + title: 'Yoga for Beginners', + }, + }, + ], + agendaItemRefetch: jest.fn(), + agendaItemCategories: [ + { + _id: 'agendaCategory1', + name: 'AgendaCategory 1', + description: 'AgendaCategory 1 Description', + createdBy: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + }, + { + _id: 'agendaCategory2', + name: 'AgendaCategory 2', + description: 'AgendaCategory 2 Description', + createdBy: { + _id: 'user1', + firstName: 'Jane', + lastName: 'Doe', + }, + }, + ], +}; + +export const props2 = { + agendaItemConnection: 'Event' as AgendaItemConnectionType, + agendaItemData: [], + agendaItemRefetch: jest.fn(), + agendaItemCategories: [], +}; diff --git a/src/components/AgendaItems/AgendaItemsCreateModal.test.tsx b/src/components/AgendaItems/AgendaItemsCreateModal.test.tsx new file mode 100644 index 0000000000..5b7339ad67 --- /dev/null +++ b/src/components/AgendaItems/AgendaItemsCreateModal.test.tsx @@ -0,0 +1,368 @@ +import React from 'react'; +import { + render, + screen, + fireEvent, + waitFor, + within, +} from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import { I18nextProvider } from 'react-i18next'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; +import { store } from 'state/store'; +import i18nForTest from 'utils/i18nForTest'; + +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; + +import AgendaItemsCreateModal from './AgendaItemsCreateModal'; +import { toast } from 'react-toastify'; +import convertToBase64 from 'utils/convertToBase64'; + +const mockFormState = { + title: 'Test Title', + description: 'Test Description', + duration: '20', + attachments: ['Test Attachment'], + urls: ['https://example.com'], + agendaItemCategoryIds: ['category'], +}; +const mockHideCreateModal = jest.fn(); +const mockSetFormState = jest.fn(); +const mockCreateAgendaItemHandler = jest.fn(); +const mockT = (key: string): string => key; +const mockAgendaItemCategories = [ + { + _id: '1', + name: 'Test Name', + description: 'Test Description', + createdBy: { + _id: '1', + firstName: 'Test', + lastName: 'User', + }, + }, + { + _id: '2', + name: 'Another Category', + description: 'Another Description', + createdBy: { + _id: '2', + firstName: 'Another', + lastName: 'Creator', + }, + }, + { + _id: '3', + name: 'Third Category', + description: 'Third Description', + createdBy: { + _id: '3', + firstName: 'Third', + lastName: 'User', + }, + }, +]; +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + error: jest.fn(), + }, +})); +jest.mock('utils/convertToBase64'); +const mockedConvertToBase64 = convertToBase64 as jest.MockedFunction< + typeof convertToBase64 +>; + +describe('AgendaItemsCreateModal', () => { + test('renders modal correctly', () => { + render( + + + + + + + + + + + , + ); + + expect(screen.getByText('agendaItemDetails')).toBeInTheDocument(); + expect(screen.getByTestId('createAgendaItemFormBtn')).toBeInTheDocument(); + expect( + screen.getByTestId('createAgendaItemModalCloseBtn'), + ).toBeInTheDocument(); + }); + + test('tests the condition for formState', async () => { + const mockFormState = { + title: 'Test Title', + description: 'Test Description', + duration: '20', + attachments: ['Test Attachment'], + urls: ['https://example.com'], + agendaItemCategoryIds: ['1'], + }; + render( + + + + + + + + + + + , + ); + + fireEvent.change(screen.getByLabelText('title'), { + target: { value: 'New title' }, + }); + + fireEvent.change(screen.getByLabelText('description'), { + target: { value: 'New description' }, + }); + + fireEvent.change(screen.getByLabelText('duration'), { + target: { value: '30' }, + }); + + fireEvent.click(screen.getByTestId('deleteUrl')); + fireEvent.click(screen.getByTestId('deleteAttachment')); + + expect(mockSetFormState).toHaveBeenCalledWith({ + ...mockFormState, + title: 'New title', + }); + expect(mockSetFormState).toHaveBeenCalledWith({ + ...mockFormState, + description: 'New description', + }); + + expect(mockSetFormState).toHaveBeenCalledWith({ + ...mockFormState, + duration: '30', + }); + + await waitFor(() => { + expect(mockSetFormState).toHaveBeenCalledWith({ + ...mockFormState, + urls: [], + }); + }); + + await waitFor(() => { + expect(mockSetFormState).toHaveBeenCalledWith({ + ...mockFormState, + attachments: [], + }); + }); + }); + test('handleAddUrl correctly adds valid URL', async () => { + render( + + + + + + + + + , + ); + + const urlInput = screen.getByTestId('urlInput'); + const linkBtn = screen.getByTestId('linkBtn'); + + fireEvent.change(urlInput, { target: { value: 'https://example.com' } }); + fireEvent.click(linkBtn); + + await waitFor(() => { + expect(mockSetFormState).toHaveBeenCalledWith({ + ...mockFormState, + urls: [...mockFormState.urls, 'https://example.com'], + }); + }); + }); + + test('shows error toast for invalid URL', async () => { + render( + + + + + + + + + + + , + ); + + const urlInput = screen.getByTestId('urlInput'); + const linkBtn = screen.getByTestId('linkBtn'); + + fireEvent.change(urlInput, { target: { value: 'invalid-url' } }); + fireEvent.click(linkBtn); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalledWith('invalidUrl'); + }); + }); + + test('shows error toast for file size exceeding limit', async () => { + render( + + + + + + + + + + + , + ); + + const fileInput = screen.getByTestId('attachment'); + const largeFile = new File( + ['a'.repeat(11 * 1024 * 1024)], + 'large-file.jpg', + ); // 11 MB file + + Object.defineProperty(fileInput, 'files', { + value: [largeFile], + }); + + fireEvent.change(fileInput); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalledWith('fileSizeExceedsLimit'); + }); + }); + + test('adds files correctly when within size limit', async () => { + mockedConvertToBase64.mockResolvedValue('base64-file'); + + render( + + + + + + + + + + + , + ); + + const fileInput = screen.getByTestId('attachment'); + const smallFile = new File(['small-file-content'], 'small-file.jpg'); // Small file + + Object.defineProperty(fileInput, 'files', { + value: [smallFile], + }); + + fireEvent.change(fileInput); + + await waitFor(() => { + expect(mockSetFormState).toHaveBeenCalledWith({ + ...mockFormState, + attachments: [...mockFormState.attachments, 'base64-file'], + }); + }); + }); + test('renders autocomplete and selects categories correctly', async () => { + render( + + + + + + + + + + + , + ); + + const autocomplete = screen.getByTestId('categorySelect'); + expect(autocomplete).toBeInTheDocument(); + + const input = within(autocomplete).getByRole('combobox'); + fireEvent.mouseDown(input); + + const options = screen.getAllByRole('option'); + expect(options).toHaveLength(mockAgendaItemCategories.length); + + fireEvent.click(options[0]); + fireEvent.click(options[1]); + }); +}); diff --git a/src/components/AgendaItems/AgendaItemsCreateModal.tsx b/src/components/AgendaItems/AgendaItemsCreateModal.tsx new file mode 100644 index 0000000000..a37ab329a2 --- /dev/null +++ b/src/components/AgendaItems/AgendaItemsCreateModal.tsx @@ -0,0 +1,330 @@ +import React, { useState, useEffect } from 'react'; +import { Modal, Form, Button, Row, Col } from 'react-bootstrap'; +import { Autocomplete, TextField } from '@mui/material'; + +import { FaLink, FaTrash } from 'react-icons/fa'; +import { toast } from 'react-toastify'; +import styles from './AgendaItemsContainer.module.css'; +import type { ChangeEvent } from 'react'; +import type { InterfaceAgendaItemCategoryInfo } from 'utils/interfaces'; +import convertToBase64 from 'utils/convertToBase64'; + +interface InterfaceFormStateType { + agendaItemCategoryIds: string[]; + title: string; + description: string; + duration: string; + attachments: string[]; + urls: string[]; +} + +interface InterfaceAgendaItemsCreateModalProps { + agendaItemCreateModalIsOpen: boolean; + hideCreateModal: () => void; + formState: InterfaceFormStateType; + setFormState: (state: React.SetStateAction) => void; + createAgendaItemHandler: (e: ChangeEvent) => Promise; + t: (key: string) => string; + agendaItemCategories: InterfaceAgendaItemCategoryInfo[] | undefined; +} + +/** + * Component for creating a new agenda item. + * Displays a modal form where users can input details for a new agenda item, including title, description, duration, categories, URLs, and attachments. + * + * @param agendaItemCreateModalIsOpen - Boolean flag indicating if the modal is open. + * @param hideCreateModal - Function to close the modal. + * @param formState - Current state of the form fields. + * @param setFormState - Function to update the form state. + * @param createAgendaItemHandler - Function to handle form submission. + * @param t - Function for translating text based on keys. + * @param agendaItemCategories - List of agenda item categories for selection. + */ +const AgendaItemsCreateModal: React.FC< + InterfaceAgendaItemsCreateModalProps +> = ({ + agendaItemCreateModalIsOpen, + hideCreateModal, + formState, + setFormState, + createAgendaItemHandler, + t, + agendaItemCategories, +}) => { + const [newUrl, setNewUrl] = useState(''); + + useEffect(() => { + // Ensure URLs and attachments do not have empty or invalid entries + setFormState((prevState) => ({ + ...prevState, + urls: prevState.urls.filter((url) => url.trim() !== ''), + attachments: prevState.attachments.filter((att) => att !== ''), + })); + }, []); + + /** + * Validates if a given URL is in a correct format. + * + * @param url - URL string to validate. + * @returns True if the URL is valid, false otherwise. + */ + const isValidUrl = (url: string): boolean => { + // Regular expression for basic URL validation + const urlRegex = /^(ftp|http|https):\/\/[^ "]+$/; + return urlRegex.test(url); + }; + + /** + * Handles adding a new URL to the form state. + * + * Checks if the URL is valid before adding it. + */ + const handleAddUrl = (): void => { + if (newUrl.trim() !== '' && isValidUrl(newUrl.trim())) { + setFormState({ + ...formState, + urls: [...formState.urls.filter((url) => url.trim() !== ''), newUrl], + }); + setNewUrl(''); + } else { + toast.error(t('invalidUrl')); + } + }; + + /** + * Handles removing a URL from the form state. + * + * @param url - URL to remove. + */ + const handleRemoveUrl = (url: string): void => { + setFormState({ + ...formState, + urls: formState.urls.filter((item) => item !== url), + }); + }; + + /** + * Handles file selection and converts files to base64 before updating the form state. + * + * @param e - File input change event. + */ + const handleFileChange = async ( + e: React.ChangeEvent, + ): Promise => { + const target = e.target as HTMLInputElement; + if (target.files) { + const files = Array.from(target.files); + let totalSize = 0; + files.forEach((file) => { + totalSize += file.size; + }); + if (totalSize > 10 * 1024 * 1024) { + toast.error(t('fileSizeExceedsLimit')); + return; + } + const base64Files = await Promise.all( + files.map(async (file) => await convertToBase64(file)), + ); + setFormState({ + ...formState, + attachments: [...formState.attachments, ...base64Files], + }); + } + }; + + /** + * Handles removing an attachment from the form state. + * + * @param attachment - Attachment to remove. + */ + const handleRemoveAttachment = (attachment: string): void => { + setFormState({ + ...formState, + attachments: formState.attachments.filter((item) => item !== attachment), + }); + }; + + return ( + + +

{t('agendaItemDetails')}

+ +
+ +
+ + + formState.agendaItemCategoryIds.includes(category._id), + ) || [] + } + filterSelectedOptions={true} + getOptionLabel={( + category: InterfaceAgendaItemCategoryInfo, + ): string => category.name} + onChange={(_, newCategories): void => { + setFormState({ + ...formState, + agendaItemCategoryIds: newCategories.map( + (category) => category._id, + ), + }); + }} + renderInput={(params) => ( + + )} + /> + + + + + {t('title')} + + setFormState({ ...formState, title: e.target.value }) + } + /> + + + + + {t('duration')} + + setFormState({ ...formState, duration: e.target.value }) + } + /> + + + + + {t('description')} + + setFormState({ ...formState, description: e.target.value }) + } + /> + + + + {t('url')} +
+ setNewUrl(e.target.value)} + /> + +
+ + {formState.urls.map((url, index) => ( +
  • + + + {url.length > 50 ? url.substring(0, 50) + '...' : url} + + +
  • + ))} +
    + + {t('attachments')} + + {t('attachmentLimit')} + + {formState.attachments && ( +
    + {formState.attachments.map((attachment, index) => ( +
    + {attachment.includes('video') ? ( + + ) : ( + Attachment preview + )} + +
    + ))} +
    + )} + + +
    +
    + ); +}; + +export default AgendaItemsCreateModal; diff --git a/src/components/AgendaItems/AgendaItemsDeleteModal.tsx b/src/components/AgendaItems/AgendaItemsDeleteModal.tsx new file mode 100644 index 0000000000..cba3b29446 --- /dev/null +++ b/src/components/AgendaItems/AgendaItemsDeleteModal.tsx @@ -0,0 +1,73 @@ +import React from 'react'; +import { Modal, Button } from 'react-bootstrap'; +import styles from './AgendaItemsContainer.module.css'; + +interface InterfaceAgendaItemsDeleteModalProps { + agendaItemDeleteModalIsOpen: boolean; + toggleDeleteModal: () => void; + deleteAgendaItemHandler: () => Promise; + t: (key: string) => string; + tCommon: (key: string) => string; +} + +/** + * Modal component for confirming the deletion of an agenda item. + * Displays a confirmation dialog when a user attempts to delete an agenda item. + * + * @param agendaItemDeleteModalIsOpen - Boolean flag indicating if the modal is open. + * @param toggleDeleteModal - Function to toggle the visibility of the modal. + * @param deleteAgendaItemHandler - Function to handle the deletion of the agenda item. + * @param t - Function for translating text based on keys. + * @param tCommon - Function for translating common text keys. + */ +const AgendaItemsDeleteModal: React.FC< + InterfaceAgendaItemsDeleteModalProps +> = ({ + agendaItemDeleteModalIsOpen, + toggleDeleteModal, + deleteAgendaItemHandler, + t, + tCommon, +}) => { + return ( + + + + {t('deleteAgendaItem')} + + + +

    {t('deleteAgendaItemMsg')}

    +
    + + + + +
    + ); +}; + +export default AgendaItemsDeleteModal; diff --git a/src/components/AgendaItems/AgendaItemsPreviewModal.test.tsx b/src/components/AgendaItems/AgendaItemsPreviewModal.test.tsx new file mode 100644 index 0000000000..0a7b4646ba --- /dev/null +++ b/src/components/AgendaItems/AgendaItemsPreviewModal.test.tsx @@ -0,0 +1,102 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import { I18nextProvider } from 'react-i18next'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; +import { store } from 'state/store'; +import i18nForTest from 'utils/i18nForTest'; + +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; + +import AgendaItemsPreviewModal from './AgendaItemsPreviewModal'; + +const mockFormState = { + title: 'Test Title', + description: 'Test Description', + duration: '20', + attachments: [ + 'https://example.com/video.mp4', + 'https://example.com/image.jpg', + ], + urls: [ + 'https://example.com', + 'https://thisisaverylongurlthatexceedsfiftycharacters.com/very/long/path', + ], + agendaItemCategoryIds: ['category'], + agendaItemCategoryNames: ['category'], + createdBy: { + firstName: 'Test', + lastName: 'User', + }, +}; + +const mockT = (key: string): string => key; + +describe('AgendaItemsPreviewModal', () => { + test('check url and attachment links', () => { + render( + + + + + + + + + + + , + ); + + expect(screen.getByText('Test Title')).toBeInTheDocument(); + expect(screen.getByText('Test Description')).toBeInTheDocument(); + expect(screen.getByText('20')).toBeInTheDocument(); + expect(screen.getByText('https://example.com')).toBeInTheDocument(); + + // Check attachments + const videoLink = screen.getByText( + (content, element) => + element?.tagName.toLowerCase() === 'a' && + (element as HTMLAnchorElement)?.href === + 'https://example.com/video.mp4', + ); + expect(videoLink).toBeInTheDocument(); + + const imageLink = screen.getByText( + (content, element) => + element?.tagName.toLowerCase() === 'a' && + (element as HTMLAnchorElement)?.href === + 'https://example.com/image.jpg', + ); + expect(imageLink).toBeInTheDocument(); + + // Check URLs + const shortUrlLink = screen.getByText( + (content, element) => + element?.tagName.toLowerCase() === 'a' && + (element as HTMLAnchorElement)?.href === 'https://example.com/', + ); + expect(shortUrlLink).toBeInTheDocument(); + expect(shortUrlLink).toHaveTextContent('https://example.com'); + + const longUrlLink = screen.getByText( + (content, element) => + element?.tagName.toLowerCase() === 'a' && + (element as HTMLAnchorElement)?.href === + 'https://thisisaverylongurlthatexceedsfiftycharacters.com/very/long/path', + ); + expect(longUrlLink).toBeInTheDocument(); + expect(longUrlLink).toHaveTextContent( + 'https://thisisaverylongurlthatexceedsfiftycharacte...', + ); + }); +}); diff --git a/src/components/AgendaItems/AgendaItemsPreviewModal.tsx b/src/components/AgendaItems/AgendaItemsPreviewModal.tsx new file mode 100644 index 0000000000..299165656c --- /dev/null +++ b/src/components/AgendaItems/AgendaItemsPreviewModal.tsx @@ -0,0 +1,173 @@ +import React from 'react'; +import { Modal, Form, Button } from 'react-bootstrap'; +import styles from './AgendaItemsContainer.module.css'; +import { FaLink } from 'react-icons/fa'; + +interface InterfaceFormStateType { + agendaItemCategoryIds: string[]; + agendaItemCategoryNames: string[]; + title: string; + description: string; + duration: string; + attachments: string[]; + urls: string[]; + createdBy: { + firstName: string; + lastName: string; + }; +} + +interface InterfaceAgendaItemsPreviewModalProps { + agendaItemPreviewModalIsOpen: boolean; + hidePreviewModal: () => void; + showUpdateModal: () => void; + toggleDeleteModal: () => void; + formState: InterfaceFormStateType; + t: (key: string) => string; +} + +/** + * Modal component for previewing details of an agenda item. + * Displays the details of the selected agenda item, including its categories, title, description, duration, creator, URLs, and attachments. + * Also provides options to update or delete the agenda item. + * + * @param agendaItemPreviewModalIsOpen - Boolean flag indicating if the preview modal is open. + * @param hidePreviewModal - Function to hide the preview modal. + * @param showUpdateModal - Function to show the update modal. + * @param toggleDeleteModal - Function to toggle the delete modal. + * @param formState - The current state of the form containing agenda item details. + * @param t - Function for translating text based on keys. + */ +const AgendaItemsPreviewModal: React.FC< + InterfaceAgendaItemsPreviewModalProps +> = ({ + agendaItemPreviewModalIsOpen, + hidePreviewModal, + showUpdateModal, + toggleDeleteModal, + formState, + t, +}) => { + /** + * Renders the attachments preview. + * + * @returns JSX elements for each attachment, displaying videos and images. + */ + const renderAttachments = (): JSX.Element[] => { + return formState.attachments.map((attachment, index) => ( +
    + {attachment.includes('video') ? ( + + + + ) : ( + + Attachment preview + + )} +
    + )); + }; + + /** + * Renders the URLs list. + * + * @returns JSX elements for each URL, displaying clickable links. + */ + const renderUrls = (): JSX.Element[] => { + return formState.urls.map((url, index) => ( +
  • + + + {url.length > 50 ? `${url.substring(0, 50)}...` : url} + +
  • + )); + }; + + return ( + + +

    {t('agendaItemDetails')}

    + +
    + +
    +
    +
    +

    {t('category')}

    + + {formState.agendaItemCategoryNames.join(', ')} + +
    +
    +

    {t('title')}

    + {formState.title} +
    +
    +

    {t('description')}

    + {formState.description} +
    +
    +

    {t('duration')}

    + {formState.duration} +
    +
    +

    {t('createdBy')}

    + + {`${formState.createdBy.firstName} ${formState.createdBy.lastName}`} + +
    +
    +

    {t('urls')}

    + {renderUrls()} +
    +
    +

    {t('attachments')}

    + {renderAttachments()} +
    +
    +
    + + +
    +
    +
    +
    + ); +}; + +export default AgendaItemsPreviewModal; diff --git a/src/components/AgendaItems/AgendaItemsUpdateModal.test.tsx b/src/components/AgendaItems/AgendaItemsUpdateModal.test.tsx new file mode 100644 index 0000000000..0f11ea31b2 --- /dev/null +++ b/src/components/AgendaItems/AgendaItemsUpdateModal.test.tsx @@ -0,0 +1,369 @@ +import React from 'react'; +import { + render, + screen, + fireEvent, + waitFor, + within, +} from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import { I18nextProvider } from 'react-i18next'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; +import { store } from 'state/store'; +import i18nForTest from 'utils/i18nForTest'; + +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; + +import AgendaItemsUpdateModal from './AgendaItemsUpdateModal'; +import { toast } from 'react-toastify'; +import convertToBase64 from 'utils/convertToBase64'; + +const mockFormState = { + title: 'Test Title', + description: 'Test Description', + duration: '20', + attachments: ['Test Attachment'], + urls: ['https://example.com'], + agendaItemCategoryIds: ['category'], + agendaItemCategoryNames: ['category'], + createdBy: { + firstName: 'Test', + lastName: 'User', + }, +}; + +const mockAgendaItemCategories = [ + { + _id: '1', + name: 'Test Name', + description: 'Test Description', + createdBy: { + _id: '1', + firstName: 'Test', + lastName: 'User', + }, + }, + { + _id: '2', + name: 'Another Category', + description: 'Another Description', + createdBy: { + _id: '2', + firstName: 'Another', + lastName: 'Creator', + }, + }, + { + _id: '3', + name: 'Third Category', + description: 'Third Description', + createdBy: { + _id: '3', + firstName: 'Third', + lastName: 'User', + }, + }, +]; + +const mockHideUpdateModal = jest.fn(); +const mockSetFormState = jest.fn(); +const mockUpdateAgendaItemHandler = jest.fn(); +const mockT = (key: string): string => key; + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + error: jest.fn(), + }, +})); +jest.mock('utils/convertToBase64'); +const mockedConvertToBase64 = convertToBase64 as jest.MockedFunction< + typeof convertToBase64 +>; + +describe('AgendaItemsUpdateModal', () => { + test('renders modal correctly', () => { + render( + + + + + + + + + + + , + ); + + expect(screen.getByText('updateAgendaItem')).toBeInTheDocument(); + expect(screen.getByTestId('updateAgendaItemBtn')).toBeInTheDocument(); + expect( + screen.getByTestId('updateAgendaItemModalCloseBtn'), + ).toBeInTheDocument(); + }); + + test('tests the condition for formState.title and formState.description', async () => { + render( + + + + + + + + + + + , + ); + + fireEvent.change(screen.getByLabelText('title'), { + target: { value: 'New title' }, + }); + + fireEvent.change(screen.getByLabelText('description'), { + target: { value: 'New description' }, + }); + + fireEvent.change(screen.getByLabelText('duration'), { + target: { value: '30' }, + }); + + fireEvent.click(screen.getByTestId('deleteUrl')); + fireEvent.click(screen.getByTestId('deleteAttachment')); + + expect(mockSetFormState).toHaveBeenCalledWith({ + ...mockFormState, + title: 'New title', + }); + expect(mockSetFormState).toHaveBeenCalledWith({ + ...mockFormState, + description: 'New description', + }); + + expect(mockSetFormState).toHaveBeenCalledWith({ + ...mockFormState, + duration: '30', + }); + + await waitFor(() => { + expect(mockSetFormState).toHaveBeenCalledWith({ + ...mockFormState, + urls: [], + }); + }); + + await waitFor(() => { + expect(mockSetFormState).toHaveBeenCalledWith({ + ...mockFormState, + attachments: [], + }); + }); + }); + + test('handleAddUrl correctly adds valid URL', async () => { + render( + + + + + + + + + , + ); + + const urlInput = screen.getByTestId('urlInput'); + const linkBtn = screen.getByTestId('linkBtn'); + + fireEvent.change(urlInput, { target: { value: 'https://example.com' } }); + fireEvent.click(linkBtn); + + await waitFor(() => { + expect(mockSetFormState).toHaveBeenCalledWith({ + ...mockFormState, + urls: [...mockFormState.urls, 'https://example.com'], + }); + }); + }); + + test('shows error toast for invalid URL', async () => { + render( + + + + + + + + + + + , + ); + + const urlInput = screen.getByTestId('urlInput'); + const linkBtn = screen.getByTestId('linkBtn'); + + fireEvent.change(urlInput, { target: { value: 'invalid-url' } }); + fireEvent.click(linkBtn); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalledWith('invalidUrl'); + }); + }); + + test('shows error toast for file size exceeding limit', async () => { + render( + + + + + + + + + + + , + ); + + const fileInput = screen.getByTestId('attachment'); + const largeFile = new File( + ['a'.repeat(11 * 1024 * 1024)], + 'large-file.jpg', + ); // 11 MB file + + Object.defineProperty(fileInput, 'files', { + value: [largeFile], + }); + + fireEvent.change(fileInput); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalledWith('fileSizeExceedsLimit'); + }); + }); + + test('adds files correctly when within size limit', async () => { + mockedConvertToBase64.mockResolvedValue('base64-file'); + + render( + + + + + + + + + + + , + ); + + const fileInput = screen.getByTestId('attachment'); + const smallFile = new File(['small-file-content'], 'small-file.jpg'); // Small file + + Object.defineProperty(fileInput, 'files', { + value: [smallFile], + }); + + fireEvent.change(fileInput); + + await waitFor(() => { + expect(mockSetFormState).toHaveBeenCalledWith({ + ...mockFormState, + attachments: [...mockFormState.attachments, 'base64-file'], + }); + }); + }); + test('renders autocomplete and selects categories correctly', async () => { + render( + + + + + + + + + + + , + ); + + const autocomplete = screen.getByTestId('categorySelect'); + expect(autocomplete).toBeInTheDocument(); + + const input = within(autocomplete).getByRole('combobox'); + fireEvent.mouseDown(input); + + const options = screen.getAllByRole('option'); + expect(options).toHaveLength(mockAgendaItemCategories.length); + + fireEvent.click(options[0]); + fireEvent.click(options[1]); + }); +}); diff --git a/src/components/AgendaItems/AgendaItemsUpdateModal.tsx b/src/components/AgendaItems/AgendaItemsUpdateModal.tsx new file mode 100644 index 0000000000..7761c912ca --- /dev/null +++ b/src/components/AgendaItems/AgendaItemsUpdateModal.tsx @@ -0,0 +1,334 @@ +import React, { useState, useEffect } from 'react'; +import { Modal, Form, Button, Row, Col } from 'react-bootstrap'; +import type { ChangeEvent } from 'react'; +import { Autocomplete, TextField } from '@mui/material'; +import { FaLink, FaTrash } from 'react-icons/fa'; +import { toast } from 'react-toastify'; +import convertToBase64 from 'utils/convertToBase64'; + +import styles from './AgendaItemsContainer.module.css'; +import type { InterfaceAgendaItemCategoryInfo } from 'utils/interfaces'; + +interface InterfaceFormStateType { + agendaItemCategoryIds: string[]; + agendaItemCategoryNames: string[]; + title: string; + description: string; + duration: string; + attachments: string[]; + urls: string[]; + createdBy: { + firstName: string; + lastName: string; + }; +} + +interface InterfaceAgendaItemsUpdateModalProps { + agendaItemUpdateModalIsOpen: boolean; + hideUpdateModal: () => void; + formState: InterfaceFormStateType; + setFormState: (state: React.SetStateAction) => void; + updateAgendaItemHandler: (e: ChangeEvent) => Promise; + t: (key: string) => string; + agendaItemCategories: InterfaceAgendaItemCategoryInfo[] | undefined; +} + +/** + * Modal component for updating details of an agenda item. + * Provides a form to update the agenda item's title, description, duration, categories, URLs, and attachments. + * Also includes functionality to add, remove URLs and attachments. + * + * @param agendaItemUpdateModalIsOpen - Boolean flag indicating if the update modal is open. + * @param hideUpdateModal - Function to hide the update modal. + * @param formState - The current state of the form containing agenda item details. + * @param setFormState - Function to update the form state. + * @param updateAgendaItemHandler - Handler function for submitting the form. + * @param t - Function for translating text based on keys. + * @param agendaItemCategories - List of agenda item categories for selection. + */ +const AgendaItemsUpdateModal: React.FC< + InterfaceAgendaItemsUpdateModalProps +> = ({ + agendaItemUpdateModalIsOpen, + hideUpdateModal, + formState, + setFormState, + updateAgendaItemHandler, + t, + agendaItemCategories, +}) => { + const [newUrl, setNewUrl] = useState(''); + + useEffect(() => { + setFormState((prevState) => ({ + ...prevState, + urls: prevState.urls.filter((url) => url.trim() !== ''), + attachments: prevState.attachments.filter((att) => att !== ''), + })); + }, []); + + /** + * Validates if a given URL is in a correct format. + * + * @param url - The URL to validate. + * @returns True if the URL is valid, false otherwise. + */ + const isValidUrl = (url: string): boolean => { + // Regular expression for basic URL validation + const urlRegex = /^(ftp|http|https):\/\/[^ "]+$/; + return urlRegex.test(url); + }; + + /** + * Handles adding a new URL to the form state. + * Displays an error toast if the URL is invalid. + */ + const handleAddUrl = (): void => { + if (newUrl.trim() !== '' && isValidUrl(newUrl.trim())) { + setFormState({ + ...formState, + urls: [...formState.urls.filter((url) => url.trim() !== ''), newUrl], + }); + setNewUrl(''); + } else { + toast.error(t('invalidUrl')); + } + }; + + /** + * Handles removing a URL from the form state. + * + * @param url - The URL to remove. + */ + const handleRemoveUrl = (url: string): void => { + setFormState({ + ...formState, + urls: formState.urls.filter((item) => item !== url), + }); + }; + + /** + * Handles file input change event. + * Converts selected files to base64 format and updates the form state. + * Displays an error toast if the total file size exceeds the limit. + * + * @param e - The change event for file input. + */ + const handleFileChange = async ( + e: React.ChangeEvent, + ): Promise => { + const target = e.target as HTMLInputElement; + if (target.files) { + const files = Array.from(target.files); + let totalSize = 0; + files.forEach((file) => { + totalSize += file.size; + }); + if (totalSize > 10 * 1024 * 1024) { + toast.error(t('fileSizeExceedsLimit')); + return; + } + const base64Files = await Promise.all( + files.map(async (file) => await convertToBase64(file)), + ); + setFormState({ + ...formState, + attachments: [...formState.attachments, ...base64Files], + }); + } + }; + + /** + * Handles removing an attachment from the form state. + * + * @param attachment - The attachment to remove. + */ + const handleRemoveAttachment = (attachment: string): void => { + setFormState({ + ...formState, + attachments: formState.attachments.filter((item) => item !== attachment), + }); + }; + + return ( + + +

    {t('updateAgendaItem')}

    + +
    + +
    + + + formState.agendaItemCategoryIds.includes(category._id), + ) || [] + } + filterSelectedOptions={true} + getOptionLabel={( + category: InterfaceAgendaItemCategoryInfo, + ): string => category.name} + onChange={(_, newCategories): void => { + setFormState({ + ...formState, + agendaItemCategoryIds: newCategories.map( + (category) => category._id, + ), + }); + }} + renderInput={(params) => ( + + )} + /> + + + + + + {t('title')} + + setFormState({ ...formState, title: e.target.value }) + } + /> + + + + + {t('duration')} + + setFormState({ ...formState, duration: e.target.value }) + } + /> + + + + + + {t('description')} + + setFormState({ ...formState, description: e.target.value }) + } + /> + + + + {t('url')} +
    + setNewUrl(e.target.value)} + /> + +
    + + {formState.urls.map((url, index) => ( +
  • + + + {url.length > 50 ? url.substring(0, 50) + '...' : url} + + +
  • + ))} +
    + + {t('attachments')} + + {t('attachmentLimit')} + + {formState.attachments && ( +
    + {formState.attachments.map((attachment, index) => ( +
    + {attachment.includes('video') ? ( + + ) : ( + Attachment preview + )} + +
    + ))} +
    + )} + + +
    +
    + ); +}; + +export default AgendaItemsUpdateModal; diff --git a/src/components/Avatar/Avatar.module.css b/src/components/Avatar/Avatar.module.css index 14aa36e9ad..13fe1bbbc6 100644 --- a/src/components/Avatar/Avatar.module.css +++ b/src/components/Avatar/Avatar.module.css @@ -1,6 +1,9 @@ .imageContainer { - width: 56px; - height: 56px; + width: fit-content; + height: fit-content; + display: flex; + align-items: center; + justify-content: center; border-radius: 100%; } .imageContainer img { diff --git a/src/components/Avatar/Avatar.tsx b/src/components/Avatar/Avatar.tsx index 6d4cab405b..431c4a875a 100644 --- a/src/components/Avatar/Avatar.tsx +++ b/src/components/Avatar/Avatar.tsx @@ -7,19 +7,35 @@ interface InterfaceAvatarProps { name: string; alt?: string; size?: number; + containerStyle?: string; avatarStyle?: string; dataTestId?: string; radius?: number; } +/** + * A component that generates and displays an avatar based on the provided name. + * The avatar is generated using the DiceBear library with the initials style. + * + * @param name - The name used to generate the avatar. + * @param alt - Alternative text for the avatar image. + * @param size - Size of the avatar image. + * @param avatarStyle - Custom CSS class for the avatar image. + * @param dataTestId - Data-testid attribute for testing purposes. + * @param radius - Radius of the avatar corners. + * + * @returns JSX.Element - The rendered avatar image component. + */ const Avatar = ({ name, alt = 'Dummy Avatar', size, avatarStyle, + containerStyle, dataTestId, radius, }: InterfaceAvatarProps): JSX.Element => { + // Memoize the avatar creation to avoid unnecessary recalculations const avatar = useMemo(() => { return createAvatar(initials, { size: size || 128, @@ -28,10 +44,10 @@ const Avatar = ({ }).toDataUriSync(); }, [name, size]); - const svg = avatar.toString(); + const svg = avatar?.toString(); return ( -
    +
    {alt} => { - await i18next.changeLanguage(languageCode); -}; - +/** + * A dropdown component that allows users to change the application's language. + * It updates the user's language preference in the backend and stores the selection in cookies. + * + * @param props - The properties for customizing the dropdown component. + * @param parentContainerStyle - Custom style for the dropdown container. + * @param btnStyle - Custom style for the dropdown button. + * @param btnTextStyle - Custom style for the button text. + * + * @returns JSX.Element - The rendered dropdown component for changing languages. + */ const ChangeLanguageDropDown = ( props: InterfaceChangeLanguageDropDownProps, ): JSX.Element => { const currentLanguageCode = cookies.get('i18next') || 'en'; + const userId = getItem('userId'); + const [updateUser] = useMutation(UPDATE_USER_MUTATION); + + /** + * Changes the application's language and updates the user's language preference. + * + * @param languageCode - The code of the language to switch to. + */ + const changeLanguage = async (languageCode: string): Promise => { + if (userId) { + try { + await updateUser({ + variables: { + appLanguageCode: languageCode, + }, + }); + await i18next.changeLanguage(languageCode); + cookies.set('i18next', languageCode); + } catch (error) { + console.log('Error in changing language', error); + } + } + }; return ( { await act(() => { @@ -16,14 +23,44 @@ async function wait(ms = 100): Promise { }); } +const MOCKS = [ + { + request: { + query: UPDATE_USER_MUTATION, + variables: { + appLanguageCode: 'fr', + }, + }, + result: { + data: { + updateUserProfile: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: UPDATE_USER_MUTATION, + variables: { + appLanguageCode: 'hi', + }, + }, + error: new Error('An error occurred'), + }, +]; + +const link = new StaticMockLink(MOCKS, true); describe('Testing Change Language Dropdown', () => { test('Component Should be rendered properly', async () => { const { getByTestId } = render( - - - - - , + + + + + + + , ); expect(getByTestId('language-dropdown-container')).toBeInTheDocument(); @@ -51,11 +88,13 @@ describe('Testing Change Language Dropdown', () => { btnTextStyle: 'btnTextStyle', }; const { getByTestId } = render( - - - - - , + + + + + + + , ); getByTestId('language-dropdown-container').className.includes( props.parentContainerStyle, @@ -71,9 +110,11 @@ describe('Testing Change Language Dropdown', () => { }); render( - - - , + + + + + , ); await wait(); @@ -83,24 +124,35 @@ describe('Testing Change Language Dropdown', () => { test('Testing change language functionality', async () => { Object.defineProperty(window.document, 'cookie', { writable: true, - value: 'i18next=en', + value: 'i18next=sp', }); + setItem('userId', '1'); const { getByTestId } = render( - - - , + + + + + , ); userEvent.click(getByTestId('language-dropdown-btn')); await wait(); - languages.map((language) => { - const changeLanguageBtn = getByTestId( - `change-language-btn-${language.code}`, - ); - expect(changeLanguageBtn).toBeInTheDocument(); - userEvent.click(changeLanguageBtn); - expect(cookies.get('i18next')).toBe(language.code); - }); + const changeLanguageBtn = getByTestId(`change-language-btn-fr`); + await wait(); + expect(changeLanguageBtn).toBeInTheDocument(); + await wait(); + userEvent.click(changeLanguageBtn); + await wait(); + expect(cookies.get('i18next')).toBe('fr'); + await wait(); + userEvent.click(getByTestId('language-dropdown-btn')); + await wait(); + const changeLanguageBtnHi = getByTestId(`change-language-btn-hi`); + await wait(); + expect(changeLanguageBtnHi).toBeInTheDocument(); + await wait(); + userEvent.click(changeLanguageBtnHi); + await wait(); }); }); diff --git a/src/components/CheckIn/CheckInModal.tsx b/src/components/CheckIn/CheckInModal.tsx index 6b4e5425c0..8c75bab598 100644 --- a/src/components/CheckIn/CheckInModal.tsx +++ b/src/components/CheckIn/CheckInModal.tsx @@ -13,26 +13,48 @@ import type { GridColDef, GridRowHeightReturnValue } from '@mui/x-data-grid'; import { DataGrid } from '@mui/x-data-grid'; import TextField from '@mui/material/TextField'; -export const CheckInModal = (props: InterfaceModalProp): JSX.Element => { +/** + * Modal component for managing event check-ins. Displays a list of attendees + * and their check-in statuses, allowing for filtering by user name. + * + * @param show - Boolean indicating whether the modal is visible. + * @param eventId - ID of the event whose check-ins are to be displayed. + * @param handleClose - Function to call when the modal is closed. + * + * @returns JSX.Element - The rendered modal component. + */ +export const CheckInModal = ({ + show, + eventId, + handleClose, +}: InterfaceModalProp): JSX.Element => { + // State to hold the data for the table const [tableData, setTableData] = useState([]); + // State for search filter input const [userFilterQuery, setUserFilterQuery] = useState(''); + + // State for filter model used in DataGrid const [filterQueryModel, setFilterQueryModel] = useState({ items: [{ field: 'userName', operator: 'contains', value: '' }], }); + // Query to get check-in data from the server const { data: checkInData, loading: checkInLoading, refetch: checkInRefetch, } = useQuery(EVENT_CHECKINS, { - variables: { id: props.eventId }, + variables: { id: eventId }, }); + // Effect runs whenever checkInData, eventId, or checkInLoading changes useEffect(() => { - checkInRefetch(); - if (checkInLoading) setTableData([]); - else + checkInRefetch(); // Refetch data when component mounts or updates + if (checkInLoading) { + setTableData([]); // Clear table data while loading + } else { + // Map the check-in data to table rows setTableData( checkInData.event.attendeesCheckInStatus.map( (checkIn: InterfaceAttendeeCheckIn) => ({ @@ -43,26 +65,29 @@ export const CheckInModal = (props: InterfaceModalProp): JSX.Element => { name: `${checkIn.user.firstName} ${checkIn.user.lastName}`, userId: checkIn.user._id, checkIn: checkIn.checkIn, - eventId: props.eventId, + eventId, }, }), ), ); - }, [checkInData, props.eventId, checkInLoading]); + } + }, [checkInData, eventId, checkInLoading]); + // Define columns for the DataGrid const columns: GridColDef[] = [ - { field: 'userName', headerName: 'User', width: 300 }, + { field: 'userName', headerName: 'User', width: 300 }, // Column for user names { field: 'checkInData', headerName: 'Check In Status', width: 400, renderCell: (props) => ( + // Render a custom row component for check-in status ), }, ]; - // Render the loading screen + // Show a loading indicator while data is loading if (checkInLoading) { return ( <> @@ -70,11 +95,12 @@ export const CheckInModal = (props: InterfaceModalProp): JSX.Element => { ); } + return ( <> { +/** + * Wrapper component that displays a button to open the CheckInModal. + * + * @param eventId - The ID of the event for which check-in management is being handled. + * + * @returns JSX.Element - The rendered CheckInWrapper component. + */ +export const CheckInWrapper = ({ eventId }: PropType): JSX.Element => { const [showModal, setShowModal] = useState(false); return ( @@ -33,7 +40,7 @@ export const CheckInWrapper = (props: PropType): JSX.Element => { setShowModal(false)} - eventId={props.eventId} + eventId={eventId} /> )} diff --git a/src/components/CheckIn/TableRow.test.tsx b/src/components/CheckIn/TableRow.test.tsx index 8d41f1036b..14c3d20c29 100644 --- a/src/components/CheckIn/TableRow.test.tsx +++ b/src/components/CheckIn/TableRow.test.tsx @@ -13,7 +13,11 @@ import { MockedProvider } from '@apollo/react-testing'; import { checkInMutationSuccess, checkInMutationUnsuccess } from './mocks'; describe('Testing Table Row for CheckIn Table', () => { - test('If the user in not checked in, button to check in should be displayed, and the user should be able to check in succesfully', async () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + test('If the user is not checked in, button to check in should be displayed, and the user should be able to check in successfully', async () => { const props = { data: { id: `123`, @@ -25,7 +29,7 @@ describe('Testing Table Row for CheckIn Table', () => { refetch: jest.fn(), }; - const { queryByText } = render( + const { findByText } = render( @@ -40,31 +44,29 @@ describe('Testing Table Row for CheckIn Table', () => { , ); - await waitFor(() => expect(queryByText('Check In')).toBeInTheDocument()); + expect(await findByText('Check In')).toBeInTheDocument(); - fireEvent.click(queryByText('Check In') as Element); + fireEvent.click(await findByText('Check In')); - await waitFor(() => - expect(queryByText('Checked in successfully!')).toBeInTheDocument(), - ); + expect(await findByText('Checked in successfully')).toBeInTheDocument(); }); - test('If the user in checked in, option to download tag should be shown', async () => { + test('If the user is checked in, the option to download tag should be shown', async () => { const props = { data: { - id: `123`, - name: `John Doe`, - userId: `user123`, + id: '123', + name: 'John Doe', + userId: 'user123', checkIn: { _id: '123', time: '12:00:00', }, - eventId: `event123`, + eventId: 'event123', }, refetch: jest.fn(), }; - const { queryByText } = render( + const { findByText } = render( @@ -79,26 +81,22 @@ describe('Testing Table Row for CheckIn Table', () => { , ); - // Stubbing functions required by the @pdfme to show pdfs - global.URL.createObjectURL = jest.fn(); + global.URL.createObjectURL = jest.fn(() => 'mockURL'); global.window.open = jest.fn(); - await waitFor(() => expect(queryByText('Checked In')).toBeInTheDocument()); - await waitFor(() => - expect(queryByText('Download Tag')).toBeInTheDocument(), - ); + expect(await findByText('Checked In')).toBeInTheDocument(); + expect(await findByText('Download Tag')).toBeInTheDocument(); - fireEvent.click(queryByText('Download Tag') as Element); + fireEvent.click(await findByText('Download Tag')); - await waitFor(() => - expect(queryByText('Generating pdf...')).toBeInTheDocument(), - ); - await waitFor(() => { - expect(queryByText('PDF generated successfully!')).toBeInTheDocument(); - }); + expect(await findByText('Generating pdf...')).toBeInTheDocument(); + expect(await findByText('PDF generated successfully!')).toBeInTheDocument(); + + // Cleanup mocks + jest.clearAllMocks(); }); - test('Upon failing of check in mutation, the appropiate error message should be shown', async () => { + test('Upon failing of check in mutation, the appropriate error message should be shown', async () => { const props = { data: { id: `123`, @@ -110,7 +108,7 @@ describe('Testing Table Row for CheckIn Table', () => { refetch: jest.fn(), }; - const { queryByText } = render( + const { findByText } = render( @@ -125,15 +123,11 @@ describe('Testing Table Row for CheckIn Table', () => { , ); - await waitFor(() => expect(queryByText('Check In')).toBeInTheDocument()); + expect(await findByText('Check In')).toBeInTheDocument(); - fireEvent.click(queryByText('Check In') as Element); + fireEvent.click(await findByText('Check In')); - await waitFor(() => - expect( - queryByText('There was an error in checking in!'), - ).toBeInTheDocument(), - ); - await waitFor(() => expect(queryByText('Oops')).toBeInTheDocument()); + expect(await findByText('Error checking in')).toBeInTheDocument(); + expect(await findByText('Oops')).toBeInTheDocument(); }); }); diff --git a/src/components/CheckIn/TableRow.tsx b/src/components/CheckIn/TableRow.tsx index bceaf3a49d..38d1dda912 100644 --- a/src/components/CheckIn/TableRow.tsx +++ b/src/components/CheckIn/TableRow.tsx @@ -6,7 +6,16 @@ import { MARK_CHECKIN } from 'GraphQl/Mutations/mutations'; import { toast } from 'react-toastify'; import { generate } from '@pdfme/generator'; import { tagTemplate } from './tagTemplate'; - +import { useTranslation } from 'react-i18next'; +/** + * Component that represents a single row in the check-in table. + * Allows users to mark themselves as checked in and download a tag if they are already checked in. + * + * @param data - The data for the current row, including user and event information. + * @param refetch - Function to refetch the check-in data after marking a check-in. + * + * @returns JSX.Element - The rendered TableRow component. + */ export const TableRow = ({ data, refetch, @@ -15,7 +24,12 @@ export const TableRow = ({ refetch: () => void; }): JSX.Element => { const [checkInMutation] = useMutation(MARK_CHECKIN); + const { t } = useTranslation('translation', { keyPrefix: 'checkIn' }); + /** + * Marks the user as checked in for the event. + * Displays success or error messages based on the result of the mutation. + */ const markCheckIn = (): void => { // as we do not want to clutter the UI currently with the same (only provide the most basic of operations) checkInMutation({ @@ -25,26 +39,48 @@ export const TableRow = ({ }, }) .then(() => { - toast.success('Checked in successfully!'); + toast.success(t('checkedInSuccessfully') as string); refetch(); }) .catch((err) => { - toast.error('There was an error in checking in!'); + toast.error(t('errorCheckingIn') as string); toast.error(err.message); }); }; - + /** + * Triggers a notification while generating and downloading a PDF tag. + * + * @returns A promise that resolves when the PDF is generated and opened. + */ const notify = (): Promise => toast.promise(generateTag, { pending: 'Generating pdf...', success: 'PDF generated successfully!', error: 'Error generating pdf!', }); + + /** + * Generates a PDF tag based on the provided data and opens it in a new tab. + * + * @returns A promise that resolves when the PDF is successfully generated and opened. + */ const generateTag = async (): Promise => { - const inputs = [{ name: data.name }]; - const pdf = await generate({ template: tagTemplate, inputs }); - const blob = new Blob([pdf.buffer], { type: 'application/pdf' }); - window.open(URL.createObjectURL(blob)); + try { + const inputs = [{ name: data.name }]; + const pdf = await generate({ template: tagTemplate, inputs }); + // istanbul ignore next + const blob = new Blob([pdf.buffer], { type: 'application/pdf' }); + // istanbul ignore next + const url = URL.createObjectURL(blob); + // istanbul ignore next + window.open(url); + // istanbul ignore next + toast.success('PDF generated successfully!'); + } catch (error: unknown) { + const errorMessage = + error instanceof Error ? error.message : 'Unknown error'; + toast.error(`Error generating pdf: ${errorMessage}`); + } }; return ( diff --git a/src/components/CheckIn/tagTemplate.ts b/src/components/CheckIn/tagTemplate.ts index 0af9eeeb15..4aa4475e02 100644 --- a/src/components/CheckIn/tagTemplate.ts +++ b/src/components/CheckIn/tagTemplate.ts @@ -1,4 +1,4 @@ -import { Template } from '@pdfme/generator'; +import { Template } from '@pdfme/common'; export const tagTemplate: Template = { schemas: [ diff --git a/src/components/CollapsibleDropdown/CollapsibleDropdown.test.tsx b/src/components/CollapsibleDropdown/CollapsibleDropdown.test.tsx index cfb1001e6b..efee248ffb 100644 --- a/src/components/CollapsibleDropdown/CollapsibleDropdown.test.tsx +++ b/src/components/CollapsibleDropdown/CollapsibleDropdown.test.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { act } from 'react'; import { render, screen, fireEvent } from '@testing-library/react'; import { BrowserRouter } from 'react-router-dom'; @@ -72,7 +72,9 @@ describe('Testing CollapsibleDropdown component', () => { const nonActiveDropdownBtn = screen.getByText('SubCategory 2'); // Check if dropdown is rendered with correct classes - activeDropdownBtn.click(); + act(() => { + fireEvent.click(activeDropdownBtn); + }); expect(parentDropdownBtn).toBeInTheDocument(); expect(parentDropdownBtn).toHaveClass('text-white'); expect(parentDropdownBtn).toHaveClass('btn-success'); @@ -88,15 +90,21 @@ describe('Testing CollapsibleDropdown component', () => { expect(nonActiveDropdownBtn).toHaveClass('btn-light'); // Check if dropdown is collapsed after clicking on it - fireEvent.click(parentDropdownBtn); + act(() => { + fireEvent.click(parentDropdownBtn); + }); expect(props.setShowDropdown).toHaveBeenCalledWith(false); // Check if dropdown is expanded after clicking on it again - fireEvent.click(parentDropdownBtn); + act(() => { + fireEvent.click(parentDropdownBtn); + }); expect(props.setShowDropdown).toHaveBeenCalledWith(true); - // Click on non active dropdown button and check if it navigates to the correct url - nonActiveDropdownBtn.click(); + // Click on non-active dropdown button and check if it navigates to the correct URL + act(() => { + fireEvent.click(nonActiveDropdownBtn); + }); expect(window.location.pathname).toBe('/sub-category-2'); }); }); diff --git a/src/components/CollapsibleDropdown/CollapsibleDropdown.tsx b/src/components/CollapsibleDropdown/CollapsibleDropdown.tsx index 4b85a1911b..2991c2ade5 100644 --- a/src/components/CollapsibleDropdown/CollapsibleDropdown.tsx +++ b/src/components/CollapsibleDropdown/CollapsibleDropdown.tsx @@ -12,6 +12,15 @@ export interface InterfaceCollapsibleDropdown { setShowDropdown: React.Dispatch>; } +/** + * A collapsible dropdown component that toggles visibility of sub-targets. + * + * @param showDropdown - Boolean indicating whether the dropdown is visible or not. + * @param target - Object containing the target information, including the name and sub-targets. + * @param setShowDropdown - Function to toggle the visibility of the dropdown. + * + * @returns JSX.Element - The rendered CollapsibleDropdown component. + */ const collapsibleDropdown = ({ target, showDropdown, @@ -22,6 +31,7 @@ const collapsibleDropdown = ({ const navigate = useNavigate(); const location = useLocation(); useEffect(() => { + // Show dropdown if the current path includes 'orgstore', otherwise hide it. if (location.pathname.includes('orgstore')) { setShowDropdown(true); } else { diff --git a/src/components/ContriStats/ContriStats.test.tsx b/src/components/ContriStats/ContriStats.test.tsx index 3164c880c8..8edb853684 100644 --- a/src/components/ContriStats/ContriStats.test.tsx +++ b/src/components/ContriStats/ContriStats.test.tsx @@ -14,7 +14,6 @@ const client: ApolloClient = new ApolloClient({ describe('Testing Contribution Stats', () => { const props = { - key: '123', id: '234', recentAmount: '200', highestAmount: '500', diff --git a/src/components/ContriStats/ContriStats.tsx b/src/components/ContriStats/ContriStats.tsx index 7891878335..a2db307d91 100644 --- a/src/components/ContriStats/ContriStats.tsx +++ b/src/components/ContriStats/ContriStats.tsx @@ -4,14 +4,20 @@ import { useTranslation } from 'react-i18next'; import styles from './ContriStats.module.css'; interface InterfaceContriStatsProps { - key: string; id: string; recentAmount: string; highestAmount: string; totalAmount: string; } -function contriStats(props: InterfaceContriStatsProps): JSX.Element { +/** + * A component that displays contribution statistics. + * + * @param props - The properties passed to the component, including `recentAmount`, `highestAmount`, and `totalAmount`. + * + * @returns JSX.Element - The rendered component displaying the contribution stats. + */ +function ContriStats(props: InterfaceContriStatsProps): JSX.Element { const { t } = useTranslation('translation', { keyPrefix: 'contriStats', }); @@ -30,4 +36,4 @@ function contriStats(props: InterfaceContriStatsProps): JSX.Element { ); } -export default contriStats; +export default ContriStats; diff --git a/src/components/CurrentHourIndicator/CurrentHourIndicator.tsx b/src/components/CurrentHourIndicator/CurrentHourIndicator.tsx index 9e4a85454a..98e02bbf5f 100644 --- a/src/components/CurrentHourIndicator/CurrentHourIndicator.tsx +++ b/src/components/CurrentHourIndicator/CurrentHourIndicator.tsx @@ -1,6 +1,11 @@ import React from 'react'; import styles from './CurrentHourIndicator.module.css'; +/** + * A component that displays an indicator for the current hour. + * + * @returns JSX.Element - The rendered component showing the current hour indicator. + */ const CurrentHourIndicator = (): JSX.Element => { return (
    diff --git a/src/components/DeleteOrg/DeleteOrg.test.tsx b/src/components/DeleteOrg/DeleteOrg.test.tsx deleted file mode 100644 index d9ac99f3ad..0000000000 --- a/src/components/DeleteOrg/DeleteOrg.test.tsx +++ /dev/null @@ -1,248 +0,0 @@ -import React from 'react'; -import { MockedProvider } from '@apollo/react-testing'; -import { render, screen } from '@testing-library/react'; -import 'jest-location-mock'; -import { I18nextProvider } from 'react-i18next'; -import { Provider } from 'react-redux'; -import { BrowserRouter } from 'react-router-dom'; - -import { - DELETE_ORGANIZATION_MUTATION, - REMOVE_SAMPLE_ORGANIZATION_MUTATION, -} from 'GraphQl/Mutations/mutations'; -import { act } from 'react-dom/test-utils'; -import { store } from 'state/store'; -import { StaticMockLink } from 'utils/StaticMockLink'; -import i18nForTest from 'utils/i18nForTest'; -import DeleteOrg from './DeleteOrg'; -import { ToastContainer, toast } from 'react-toastify'; -import { IS_SAMPLE_ORGANIZATION_QUERY } from 'GraphQl/Queries/Queries'; -import useLocalStorage from 'utils/useLocalstorage'; - -const { setItem } = useLocalStorage(); - -async function wait(ms = 1000): Promise { - await act(async () => { - await new Promise((resolve) => setTimeout(resolve, ms)); - }); -} - -const MOCKS = [ - { - request: { - query: IS_SAMPLE_ORGANIZATION_QUERY, - variables: { - isSampleOrganizationId: '123', - }, - }, - result: { - data: { - isSampleOrganization: true, - }, - }, - }, - { - request: { - query: REMOVE_SAMPLE_ORGANIZATION_MUTATION, - }, - result: { - data: { - removeSampleOrganization: true, - }, - }, - }, - { - request: { - query: DELETE_ORGANIZATION_MUTATION, - variables: { - id: '456', - }, - }, - result: { - data: { - removeOrganization: { - _id: '456', - }, - }, - }, - }, -]; - -const MOCKS_WITH_ERROR = [ - { - request: { - query: IS_SAMPLE_ORGANIZATION_QUERY, - variables: { - isSampleOrganizationId: '123', - }, - }, - result: { - data: { - isSampleOrganization: true, - }, - }, - }, - { - request: { - query: DELETE_ORGANIZATION_MUTATION, - variables: { - id: '456', - }, - }, - error: new Error('Failed to delete organization'), - }, - { - request: { - query: REMOVE_SAMPLE_ORGANIZATION_MUTATION, - }, - error: new Error('Failed to delete sample organization'), - }, -]; -const mockNavgatePush = jest.fn(); -let mockURL = '123'; -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useParams: () => ({ orgId: mockURL }), - useNavigate: () => mockNavgatePush, -})); - -const link = new StaticMockLink(MOCKS, true); -const link2 = new StaticMockLink(MOCKS_WITH_ERROR, true); - -afterEach(() => { - localStorage.clear(); -}); - -describe('Delete Organization Component', () => { - test('should be able to Toggle Delete Organization Modal', async () => { - mockURL = '456'; - setItem('SuperAdmin', true); - render( - - - - - - - - - - , - ); - await wait(); - screen.getByTestId(/openDeleteModalBtn/i).click(); - expect(screen.getByTestId(/orgDeleteModal/i)).toBeInTheDocument(); - screen.getByTestId(/closeDelOrgModalBtn/i).click(); - await act(async () => { - expect(screen.queryByTestId(/orgDeleteModal/i)).not.toHaveFocus(); - }); - }); - - test('should be able to Toggle Delete Organization Modal When Organization is Sample Organization', async () => { - mockURL = '123'; - setItem('SuperAdmin', true); - render( - - - - - - - - - - , - ); - await wait(); - screen.getByTestId(/openDeleteModalBtn/i).click(); - expect(screen.getByTestId(/orgDeleteModal/i)).toBeInTheDocument(); - screen.getByTestId(/closeDelOrgModalBtn/i).click(); - await act(async () => { - expect(screen.queryByTestId(/orgDeleteModal/i)).not.toHaveFocus(); - }); - }); - - test('Delete organization functionality should work properly', async () => { - mockURL = '456'; - setItem('SuperAdmin', true); - render( - - - - - - - - - , - ); - await wait(); - screen.getByTestId(/openDeleteModalBtn/i).click(); - screen.getByTestId(/deleteOrganizationBtn/i).click(); - }); - - test('Delete organization functionality should work properly for sample org', async () => { - mockURL = '123'; - setItem('SuperAdmin', true); - render( - - - - - - - - - , - ); - await wait(); - screen.getByTestId(/openDeleteModalBtn/i).click(); - screen.getByTestId(/deleteOrganizationBtn/i).click(); - await wait(2000); - expect(mockNavgatePush).toHaveBeenCalledWith('/orglist'); - }); - - test('Error handling for IS_SAMPLE_ORGANIZATION_QUERY mock', async () => { - mockURL = '123'; - setItem('SuperAdmin', true); - jest.spyOn(toast, 'error'); - render( - - - - - - - - - , - ); - await wait(); - screen.getByTestId(/openDeleteModalBtn/i).click(); - screen.getByTestId(/deleteOrganizationBtn/i).click(); - await wait(); - expect(toast.error).toHaveBeenCalledWith( - 'Failed to delete sample organization', - ); - }); - - test('Error handling for DELETE_ORGANIZATION_MUTATION mock', async () => { - mockURL = '456'; - setItem('SuperAdmin', true); - render( - - - - - - - - - , - ); - await wait(); - screen.getByTestId(/openDeleteModalBtn/i).click(); - screen.getByTestId(/deleteOrganizationBtn/i).click(); - await wait(); - }); -}); diff --git a/src/components/DynamicDropDown/DynamicDropDown.tsx b/src/components/DynamicDropDown/DynamicDropDown.tsx index 57a5e1d93f..c72cd41bdb 100644 --- a/src/components/DynamicDropDown/DynamicDropDown.tsx +++ b/src/components/DynamicDropDown/DynamicDropDown.tsx @@ -2,6 +2,9 @@ import React from 'react'; import { Dropdown } from 'react-bootstrap'; import styles from './DynamicDropDown.module.css'; +/** + * Props for the DynamicDropDown component. + */ interface InterfaceChangeDropDownProps { parentContainerStyle?: string; btnStyle?: string; @@ -28,8 +31,43 @@ const DynamicDropDown = >( } else { props?.setFormState({ ...props?.formState, [props?.fieldName]: value }); } +/** + * A dynamic dropdown component that allows users to select an option. + * + * This component renders a dropdown with a toggle button. Clicking the button + * opens a menu with options. When an option is selected, it updates the form state. + * + * @param parentContainerStyle - Optional CSS class for styling the container. + * @param btnStyle - Optional CSS class for styling the dropdown button. + * @param setFormState - Function to update the form state with the selected option. + * @param formState - Current state of the form, used to determine the selected value. + * @param fieldOptions - Options to display in the dropdown. Each option has a value and a label. + * @param fieldName - The name of the field, used for labeling and key identification. + * @returns JSX.Element - The rendered dropdown component. + */ +const DynamicDropDown = ({ + parentContainerStyle = '', + btnStyle = '', + setFormState, + formState, + fieldOptions, + fieldName, +}: InterfaceChangeDropDownProps): JSX.Element => { + /** + * Updates the form state when a dropdown option is selected. + * + * @param value - The value of the selected option. + */ + const handleFieldChange = (value: string): void => { + setFormState({ ...formState, [fieldName]: value }); }; + /** + * Retrieves the label for a given value from the options. + * + * @param value - The value for which to get the label. + * @returns The label corresponding to the value, or 'None' if not found. + */ const getLabel = (value: string): string => { const selectedOption = props?.fieldOptions.find( (option) => option.value === value, diff --git a/src/components/EditCustomFieldDropDown/EditCustomFieldDropDown.test.tsx b/src/components/EditCustomFieldDropDown/EditCustomFieldDropDown.test.tsx index 2e3c52ad38..19d2249a43 100644 --- a/src/components/EditCustomFieldDropDown/EditCustomFieldDropDown.test.tsx +++ b/src/components/EditCustomFieldDropDown/EditCustomFieldDropDown.test.tsx @@ -1,13 +1,13 @@ import type { Dispatch, SetStateAction } from 'react'; -import React from 'react'; -import { act, render } from '@testing-library/react'; +import React, { act } from 'react'; +import { render } from '@testing-library/react'; import { BrowserRouter } from 'react-router-dom'; import EditOrgCustomFieldDropDown from './EditCustomFieldDropDown'; -import type { InterfaceCustomFieldData } from 'components/OrgProfileFieldSettings/OrgProfileFieldSettings'; import userEvent from '@testing-library/user-event'; import availableFieldTypes from 'utils/fieldTypes'; import { I18nextProvider } from 'react-i18next'; import i18nForTest from 'utils/i18nForTest'; +import type { InterfaceCustomFieldData } from 'utils/interfaces'; async function wait(ms = 100): Promise { await act(() => { diff --git a/src/components/EditCustomFieldDropDown/EditCustomFieldDropDown.tsx b/src/components/EditCustomFieldDropDown/EditCustomFieldDropDown.tsx index 7a81e78e27..2350d2c9c4 100644 --- a/src/components/EditCustomFieldDropDown/EditCustomFieldDropDown.tsx +++ b/src/components/EditCustomFieldDropDown/EditCustomFieldDropDown.tsx @@ -2,9 +2,12 @@ import React from 'react'; import type { SetStateAction, Dispatch } from 'react'; import { Dropdown } from 'react-bootstrap'; import availableFieldTypes from 'utils/fieldTypes'; -import type { InterfaceCustomFieldData } from 'components/OrgProfileFieldSettings/OrgProfileFieldSettings'; import { useTranslation } from 'react-i18next'; +import type { InterfaceCustomFieldData } from 'utils/interfaces'; +/** + * Props for the EditOrgCustomFieldDropDown component. + */ interface InterfaceEditCustomFieldDropDownProps { customFieldData: InterfaceCustomFieldData; setCustomFieldData: Dispatch>; @@ -13,6 +16,20 @@ interface InterfaceEditCustomFieldDropDownProps { btnTextStyle?: string; } +/** + * A dropdown component for editing custom field types. + * + * This component displays a dropdown menu that allows users to select a custom field type. + * It shows the current type of the field and provides a list of available types to choose from. + * When a new type is selected, it updates the custom field data. + * + * @param customFieldData - The current data of the custom field being edited. + * @param setCustomFieldData - Function to update the custom field data with the new type. + * @param parentContainerStyle - Optional CSS class to style the container of the dropdown. + * @param btnStyle - Optional CSS class to style the dropdown button. + * @param btnTextStyle - Optional CSS class to style the text inside the button. + * @returns JSX.Element - The rendered dropdown component. + */ const EditOrgCustomFieldDropDown = ({ customFieldData, setCustomFieldData, diff --git a/src/components/EventCalendar/EventCalendar.tsx b/src/components/EventCalendar/EventCalendar.tsx index c06f3c5fea..fb76eb597c 100644 --- a/src/components/EventCalendar/EventCalendar.tsx +++ b/src/components/EventCalendar/EventCalendar.tsx @@ -56,6 +56,7 @@ enum Role { interface InterfaceIOrgList { admins: { _id: string }[]; } + const Calendar: React.FC = ({ eventData, refetchEvents, @@ -125,6 +126,9 @@ const Calendar: React.FC = ({ setEvents(data); }, [eventData, orgData, userRole, userId]); + /** + * Moves the calendar view to the previous month. + */ const handlePrevMonth = (): void => { /*istanbul ignore next*/ if (currentMonth === 0) { @@ -135,6 +139,9 @@ const Calendar: React.FC = ({ } }; + /** + * Moves the calendar view to the next month. + */ const handleNextMonth = (): void => { /*istanbul ignore next*/ if (currentMonth === 11) { @@ -145,6 +152,9 @@ const Calendar: React.FC = ({ } }; + /** + * Moves the calendar view to the previous date. + */ const handlePrevDate = (): void => { /*istanbul ignore next*/ if (currentDate > 1) { @@ -188,6 +198,9 @@ const Calendar: React.FC = ({ } }; + /** + * Moves the calendar view to today's date. + */ const handleTodayButton = (): void => { /*istanbul ignore next*/ setCurrentYear(today.getFullYear()); @@ -318,7 +331,8 @@ const Calendar: React.FC = ({ ); if ( - datas.startTime?.slice(0, 2) == (index % 24).toString() && + parseInt(datas.startTime?.slice(0, 2) as string).toString() == + (index % 24).toString() && datas.startDate == dayjs(currDate).format('YYYY-MM-DD') ) { return datas; diff --git a/src/components/EventCalendar/EventHeader.test.tsx b/src/components/EventCalendar/EventHeader.test.tsx index 215182af9c..e18d066306 100644 --- a/src/components/EventCalendar/EventHeader.test.tsx +++ b/src/components/EventCalendar/EventHeader.test.tsx @@ -1,10 +1,9 @@ -import React from 'react'; +import React, { act } from 'react'; // Import act for async testing import { render, fireEvent } from '@testing-library/react'; import EventHeader from './EventHeader'; import { ViewType } from '../../screens/OrganizationEvents/OrganizationEvents'; import { I18nextProvider } from 'react-i18next'; import i18nForTest from 'utils/i18nForTest'; -import { act } from 'react-dom/test-utils'; // Import act for async testing describe('EventHeader Component', () => { const viewType = ViewType.MONTH; diff --git a/src/components/EventCalendar/EventHeader.tsx b/src/components/EventCalendar/EventHeader.tsx index a4bc59596c..1e4653ebf4 100644 --- a/src/components/EventCalendar/EventHeader.tsx +++ b/src/components/EventCalendar/EventHeader.tsx @@ -5,12 +5,24 @@ import styles from './EventCalendar.module.css'; import { ViewType } from '../../screens/OrganizationEvents/OrganizationEvents'; import { useTranslation } from 'react-i18next'; +/** + * Props for the EventHeader component. + */ interface InterfaceEventHeaderProps { viewType: ViewType; handleChangeView: (item: string | null) => void; showInviteModal: () => void; } +/** + * EventHeader component displays the header for the event calendar. + * It includes a search field, view type dropdown, event type dropdown, and a button to create an event. + * + * @param viewType - The current view type of the calendar. + * @param handleChangeView - Function to handle changing the view type. + * @param showInviteModal - Function to show the invite modal for creating an event. + * @returns JSX.Element - The rendered EventHeader component. + */ function eventHeader({ viewType, handleChangeView, @@ -34,6 +46,11 @@ function eventHeader({ required className={styles.inputField} value={eventName} + /** + * Updates the event name state when the input value changes. + * + * @param e - The event object from the input change. + */ /*istanbul ignore next*/ onChange={(e) => setEventName(e.target.value)} /> diff --git a/src/components/EventCalendar/YearlyEventCalender.tsx b/src/components/EventCalendar/YearlyEventCalender.tsx index 7b7a4d4b03..63870ded3c 100644 --- a/src/components/EventCalendar/YearlyEventCalender.tsx +++ b/src/components/EventCalendar/YearlyEventCalender.tsx @@ -7,6 +7,9 @@ import type { ViewType } from 'screens/OrganizationEvents/OrganizationEvents'; import { ChevronLeft, ChevronRight } from '@mui/icons-material'; import type { InterfaceRecurrenceRule } from 'utils/recurrenceUtils'; +/** + * Interface for event data used in the calendar. + */ interface InterfaceEventListCardProps { userRole?: string; key?: string; @@ -49,12 +52,18 @@ enum Status { DELETED = 'DELETED', } +/** + * Enum for different user roles. + */ enum Role { USER = 'USER', SUPERADMIN = 'SUPERADMIN', ADMIN = 'ADMIN', } +/** + * Interface for event attendees. + */ interface InterfaceIEventAttendees { userId: string; user?: string; @@ -62,9 +71,27 @@ interface InterfaceIEventAttendees { createdAt?: Date; } +/** + * Interface for organization list. + */ interface InterfaceIOrgList { admins: { _id: string }[]; } + +/** + * Calendar component to display events for a selected year. + * + * This component renders a yearly calendar with navigation to view previous and next years. + * It displays events for each day, with functionality to expand and view details of events. + * + * @param eventData - Array of event data to display on the calendar. + * @param refetchEvents - Function to refresh the event data. + * @param orgData - Organization data to filter events. + * @param userRole - Role of the user for access control. + * @param userId - ID of the user for filtering events they are attending. + * @param viewType - Type of view for the calendar. + * @returns JSX.Element - The rendered calendar component. + */ const Calendar: React.FC = ({ eventData, refetchEvents, @@ -95,6 +122,15 @@ const Calendar: React.FC = ({ ); const [expandedY, setExpandedY] = useState(null); + /** + * Filters events based on user role, organization data, and user ID. + * + * @param eventData - Array of event data to filter. + * @param orgData - Organization data for filtering events. + * @param userRole - Role of the user for access control. + * @param userId - ID of the user for filtering events they are attending. + * @returns Filtered array of event data. + */ const filterData = ( eventData: InterfaceEventListCardProps[], orgData?: InterfaceIOrgList, @@ -137,16 +173,27 @@ const Calendar: React.FC = ({ setEvents(data); }, [eventData, orgData, userRole, userId]); + /** + * Navigates to the previous year. + */ const handlePrevYear = (): void => { /*istanbul ignore next*/ setCurrentYear(currentYear - 1); }; + /** + * Navigates to the next year. + */ const handleNextYear = (): void => { /*istanbul ignore next*/ setCurrentYear(currentYear + 1); }; + /** + * Renders the days of the month for the calendar. + * + * @returns Array of JSX elements representing the days of each month. + */ const renderMonthDays = (): JSX.Element[] => { const renderedMonths: JSX.Element[] = []; @@ -320,6 +367,11 @@ const Calendar: React.FC = ({ return renderedMonths; }; + /** + * Renders the yearly calendar with navigation buttons. + * + * @returns JSX.Element - The rendered yearly calendar component. + */ const renderYearlyCalendar = (): JSX.Element => { return (
    diff --git a/src/components/EventDashboardScreen/EventDashboardScreen.tsx b/src/components/EventDashboardScreen/EventDashboardScreen.tsx index 9b518f5e0b..11b9ec936f 100644 --- a/src/components/EventDashboardScreen/EventDashboardScreen.tsx +++ b/src/components/EventDashboardScreen/EventDashboardScreen.tsx @@ -1,15 +1,23 @@ import LeftDrawerOrg from 'components/LeftDrawerOrg/LeftDrawerOrg'; import React, { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { useDispatch, useSelector } from 'react-redux'; +import { useSelector } from 'react-redux'; import { Navigate, Outlet, useLocation, useParams } from 'react-router-dom'; import { updateTargets } from 'state/action-creators'; +import { useAppDispatch } from 'state/hooks'; import type { RootState } from 'state/reducers'; import type { TargetsType } from 'state/reducers/routesReducer'; import styles from './EventDashboardScreen.module.css'; import ProfileDropdown from 'components/ProfileDropdown/ProfileDropdown'; import useLocalStorage from 'utils/useLocalstorage'; +import type { InterfaceMapType } from 'utils/interfaces'; +/** + * The EventDashboardScreen component is the main dashboard view for event management. + * It includes navigation, a sidebar, and a profile dropdown. + * + * @returns JSX.Element - The rendered EventDashboardScreen component. + */ const EventDashboardScreen = (): JSX.Element => { const { getItem } = useLocalStorage(); const isLoggedIn = getItem('IsLoggedIn'); @@ -19,6 +27,8 @@ const EventDashboardScreen = (): JSX.Element => { const { t } = useTranslation('translation', { keyPrefix: titleKey }); const [hideDrawer, setHideDrawer] = useState(null); const { orgId } = useParams(); + + // Redirect to home if orgId is not present or if user is not logged in if (!orgId) { return ; } @@ -43,22 +53,31 @@ const EventDashboardScreen = (): JSX.Element => { ); } + // Access targets from Redux store const appRoutes: { targets: TargetsType[]; } = useSelector((state: RootState) => state.appRoutes); const { targets } = appRoutes; - const dispatch = useDispatch(); + const dispatch = useAppDispatch(); + + // Update targets when orgId changes useEffect(() => { dispatch(updateTargets(orgId)); - }, [orgId]); // Added orgId to the dependency array + }, [orgId]); + /** + * Handles window resize events to toggle the visibility of the sidebar drawer. + */ const handleResize = (): void => { if (window.innerWidth <= 820 && !hideDrawer) { setHideDrawer(true); } }; + /** + * Toggles the visibility of the sidebar drawer. + */ const toggleDrawer = (): void => { setHideDrawer(!hideDrawer); }; @@ -119,10 +138,6 @@ const EventDashboardScreen = (): JSX.Element => { export default EventDashboardScreen; -interface InterfaceMapType { - [key: string]: string; -} - const map: InterfaceMapType = { orgdash: 'dashboard', orgpeople: 'organizationPeople', diff --git a/src/components/EventListCard/EventListCard.test.tsx b/src/components/EventListCard/EventListCard.test.tsx index 22ddccd8d2..b882d5887b 100644 --- a/src/components/EventListCard/EventListCard.test.tsx +++ b/src/components/EventListCard/EventListCard.test.tsx @@ -1,12 +1,6 @@ -import React from 'react'; +import React, { act } from 'react'; import type { RenderResult } from '@testing-library/react'; -import { - act, - render, - screen, - fireEvent, - waitFor, -} from '@testing-library/react'; +import { render, screen, fireEvent, waitFor } from '@testing-library/react'; import { MockedProvider } from '@apollo/react-testing'; import userEvent from '@testing-library/user-event'; import { I18nextProvider } from 'react-i18next'; @@ -57,6 +51,8 @@ const translations = { const renderEventListCard = ( props: InterfaceEventListCardProps, ): RenderResult => { + const { key, ...restProps } = props; // Destructure the key and separate other props + return render( @@ -66,11 +62,11 @@ const renderEventListCard = ( } + element={} /> } + element={} /> { }); test('should show an error toast when the delete event mutation fails', async () => { + // Destructure key from props[1] and pass it separately to avoid spreading it + const { key, ...otherProps } = props[1]; render( @@ -887,11 +885,11 @@ describe('Testing Event List Card', () => { } + element={} /> } + element={} /> diff --git a/src/components/EventListCard/EventListCard.tsx b/src/components/EventListCard/EventListCard.tsx index 9d89647ee1..ffa508ff7c 100644 --- a/src/components/EventListCard/EventListCard.tsx +++ b/src/components/EventListCard/EventListCard.tsx @@ -5,6 +5,9 @@ import { Navigate, useParams } from 'react-router-dom'; import EventListCardModals from './EventListCardModals'; import type { InterfaceRecurrenceRule } from 'utils/recurrenceUtils'; +/** + * Props for the EventListCard component. + */ export interface InterfaceEventListCardProps { refetchEvents?: () => void; userRole?: string; @@ -33,6 +36,12 @@ export interface InterfaceEventListCardProps { }; } +/** + * Component that displays an event card with a modal for event details. + * + * @param props - The props for the EventListCard component. + * @returns The rendered EventListCard component. + */ function eventListCard(props: InterfaceEventListCardProps): JSX.Element { const { t } = useTranslation('translation', { keyPrefix: 'eventListCard', @@ -42,14 +51,22 @@ function eventListCard(props: InterfaceEventListCardProps): JSX.Element { const [eventModalIsOpen, setEventModalIsOpen] = useState(false); const { orgId } = useParams(); + + // Redirect to home if orgId is not present if (!orgId) { return ; } + /** + * Opens the event modal. + */ const showViewModal = (): void => { setEventModalIsOpen(true); }; + /** + * Closes the event modal. + */ const hideViewModal = (): void => { setEventModalIsOpen(false); }; diff --git a/src/components/EventListCard/EventListCardMocks.ts b/src/components/EventListCard/EventListCardMocks.ts index e5f7ea3227..6312b5af51 100644 --- a/src/components/EventListCard/EventListCardMocks.ts +++ b/src/components/EventListCard/EventListCardMocks.ts @@ -69,8 +69,8 @@ export const MOCKS = [ startDate: '2022-03-18', endDate: '2022-03-20', location: 'New Delhi', - startTime: '09:00:00Z', - endTime: '17:00:00Z', + startTime: '09:00:00', + endTime: '17:00:00', }, }, result: { diff --git a/src/components/EventListCard/EventListCardModals.tsx b/src/components/EventListCard/EventListCardModals.tsx index 51612f45e5..193890941c 100644 --- a/src/components/EventListCard/EventListCardModals.tsx +++ b/src/components/EventListCard/EventListCardModals.tsx @@ -37,11 +37,24 @@ enum Role { ADMIN = 'ADMIN', } +/** + * Converts a time string to a Dayjs object representing the current date with the specified time. + * @param time - A string representing the time in 'HH:mm:ss' format. + * @returns A Dayjs object with the current date and specified time. + */ const timeToDayJs = (time: string): Dayjs => { const dateTimeString = dayjs().format('YYYY-MM-DD') + ' ' + time; return dayjs(dateTimeString, { format: 'YYYY-MM-DD HH:mm:ss' }); }; +/** + * Properties for the `EventListCardModals` component. + * eventListCardProps - The properties of the event list card. + * eventModalIsOpen - Boolean indicating if the event modal is open. + * hideViewModal - Function to hide the event modal. + * t - Function for translation of text. + * tCommon - Function for translation of common text. + */ interface InterfaceEventListCardModalProps { eventListCardProps: InterfaceEventListCardProps; eventModalIsOpen: boolean; @@ -50,6 +63,12 @@ interface InterfaceEventListCardModalProps { tCommon: (key: string) => string; } +/** + * The `EventListCardModals` component displays the modals related to events, such as viewing, + * updating, and deleting events. + * @param props - The properties for the component. + * @returns A JSX element containing the event modals. + */ function EventListCardModals({ eventListCardProps, eventModalIsOpen, @@ -236,8 +255,8 @@ function EventListCardModals({ startDate: dayjs(eventStartDate).format('YYYY-MM-DD'), endDate: dayjs(eventEndDate).format('YYYY-MM-DD'), location: formState.location, - startTime: !alldaychecked ? formState.startTime + 'Z' : undefined, - endTime: !alldaychecked ? formState.endTime + 'Z' : undefined, + startTime: !alldaychecked ? formState.startTime : undefined, + endTime: !alldaychecked ? formState.endTime : undefined, recurrenceStartDate: recurringchecked ? recurringEventUpdateType === thisAndFollowingInstances && (instanceDatesChanged || recurrenceRuleChanged) @@ -265,7 +284,7 @@ function EventListCardModals({ }); if (data) { - toast.success(t('eventUpdated')); + toast.success(t('eventUpdated') as string); setRecurringEventUpdateModalIsOpen(false); hideViewModal(); if (refetchEvents) { @@ -304,7 +323,7 @@ function EventListCardModals({ }); if (data) { - toast.success(t('eventDeleted')); + toast.success(t('eventDeleted') as string); setEventDeleteModalIsOpen(false); hideViewModal(); if (refetchEvents) { diff --git a/src/components/EventManagement/Dashboard/EventDashboard.tsx b/src/components/EventManagement/Dashboard/EventDashboard.tsx index 9c662344b1..cb2c982219 100644 --- a/src/components/EventManagement/Dashboard/EventDashboard.tsx +++ b/src/components/EventManagement/Dashboard/EventDashboard.tsx @@ -10,6 +10,13 @@ import EventListCardModals from 'components/EventListCard/EventListCardModals'; import type { InterfaceEventListCardProps } from 'components/EventListCard/EventListCard'; import { formatDate } from 'utils/dateFormatter'; +/** + * Component that displays event details. + * + * @param props - The props for the EventDashboard component. + * @param eventId - The ID of the event to fetch and display. + * @returns The rendered EventDashboard component. + */ const EventDashboard = (props: { eventId: string }): JSX.Element => { const { eventId } = props; const isMounted = useRef(true); @@ -40,6 +47,12 @@ const EventDashboard = (props: { eventId: string }): JSX.Element => { }; }, []); + /** + * Formats a time string (HH:MM) to a more readable format. + * + * @param timeString - The time string to format. + * @returns - The formatted time string. + */ function formatTime(timeString: string): string { const [hours, minutes] = timeString.split(':').slice(0, 2); return `${hours}:${minutes}`; @@ -84,6 +97,11 @@ const EventDashboard = (props: { eventId: string }): JSX.Element => { creator: eventData.event.creator, }; + if (!eventData || !eventData.event) { + return ; // Fallback UI while data is loading + } + + // Render event details return (
    @@ -151,7 +169,7 @@ const EventDashboard = (props: { eventId: string }): JSX.Element => {

    Registrants:{' '} - {eventData.event.attendees.length} + {eventData?.event?.attendees?.length}

    button { - padding-top: 10px; - padding-bottom: 10px; -} -.TableImage { - object-fit: cover; - width: 50px !important; - height: 50px !important; - border-radius: 100% !important; -} -.tableHead { - background-color: #31bb6b !important; - color: white; - border-radius: 20px !important; - padding: 20px; - margin-top: 20px; -} - -.tableHead :nth-first-child() { - border-top-left-radius: 20px; -} - -.mainpageright > hr { - margin-top: 10px; - width: 100%; - margin-left: -15px; - margin-right: -15px; - margin-bottom: 20px; -} -.rowBackground { - background-color: var(--bs-white); -} -.tableHeader { - background-color: var(--bs-primary); - color: var(--bs-white); - font-size: 16px; -} -.addButton { - width: 7em; - position: absolute; - right: 1rem; - top: 1rem; -} - -.createModal { - margin-top: 20vh; - margin-left: 13vw; - max-width: 80vw; -} - -.icon { - transform: scale(1.5); - color: var(--bs-danger); - margin-bottom: 1rem; -} - -.message { - display: flex; - justify-content: center; - align-items: center; - flex-direction: column; -} - -.titlemodal { - color: var(--bs-gray-600); - font-weight: 600; - font-size: 20px; - margin-top: 1rem; - width: 65%; -} - -.editDelBtns { - display: flex; - justify-content: space-around; -} - -.greenregbtn { - margin-bottom: 20px; - margin-left: 85%; -} - -.datatable { - margin-top: 5rem; -} - -.datediv { - display: flex; -} - -@-webkit-keyframes load8 { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } -} -@keyframes load8 { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } -} diff --git a/src/components/EventManagement/EventActionItems/EventActionItems.test.tsx b/src/components/EventManagement/EventActionItems/EventActionItems.test.tsx deleted file mode 100644 index ef69796da4..0000000000 --- a/src/components/EventManagement/EventActionItems/EventActionItems.test.tsx +++ /dev/null @@ -1,628 +0,0 @@ -import React from 'react'; -import { MockedProvider } from '@apollo/react-testing'; -import { LocalizationProvider } from '@mui/x-date-pickers'; -import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; -import { act, fireEvent, render, screen } from '@testing-library/react'; -import { Provider } from 'react-redux'; -import { BrowserRouter } from 'react-router-dom'; -import userEvent from '@testing-library/user-event'; -import { I18nextProvider } from 'react-i18next'; -import EventActionItems from './EventActionItems'; -import { store } from 'state/store'; -import 'jest-location-mock'; -import { toast } from 'react-toastify'; -import i18nForTest from 'utils/i18nForTest'; -import { StaticMockLink } from 'utils/StaticMockLink'; -import { - CREATE_ACTION_ITEM_MUTATION, - UPDATE_ACTION_ITEM_MUTATION, - DELETE_ACTION_ITEM_MUTATION, -} from 'GraphQl/Mutations/ActionItemMutations'; -import { - ACTION_ITEM_CATEGORY_LIST, - MEMBERS_LIST, -} from 'GraphQl/Queries/Queries'; -import { ACTION_ITEM_LIST_BY_EVENTS } from 'GraphQl/Queries/ActionItemQueries'; - -async function wait(ms = 100): Promise { - await act(() => { - return new Promise((resolve) => { - setTimeout(resolve, ms); - }); - }); -} - -jest.mock('react-toastify', () => ({ - toast: { - success: jest.fn(), - error: jest.fn(), - }, -})); - -const MOCKS = [ - { - request: { - query: CREATE_ACTION_ITEM_MUTATION, - variables: { - assigneeId: '658930fd2caa9d8d6908745c', - actionItemCategoryId: '65f069a53b63ad266db32b3f', - eventId: '123', - preCompletionNotes: 'task to be done with high priority', - dueDate: '2024-04-05', - }, - }, - result: { - data: { - createActionItem: { - _id: 'newly_created_action_item_id', - }, - }, - }, - }, - { - request: { - query: UPDATE_ACTION_ITEM_MUTATION, - variables: { - actionItemId: '_6613ef741677gygwuyu', - assigneeId: '658930fd2caa9d8d6908745c', - preCompletionNotes: 'task to be done with high priority', - postCompletionNotes: 'Done', - dueDate: '2024-04-05', - completionDate: '2024-04-05', - isCompleted: false, - }, - }, - result: { - data: { - updateActionItem: { - _id: '_6613ef741677gygwuyu', - __typename: 'ActionItem', - }, - }, - }, - }, - { - request: { - query: DELETE_ACTION_ITEM_MUTATION, - variables: { - actionItemId: '_6613ef741677gygwuyu', - }, - }, - result: { - data: { - removeActionItem: { - _id: '_6613ef741677gygwuyu', - __typename: 'ActionItem', - }, - }, - }, - }, - { - request: { - query: ACTION_ITEM_CATEGORY_LIST, - variables: { - organizationId: '111', - }, - }, - result: { - data: { - actionItemCategoriesByOrganization: [ - { - _id: '65f069a53b63ad266db32b3f', - name: 'Default', - isDisabled: false, - __typename: 'ActionItemCategory', - }, - ], - }, - }, - }, - { - request: { - query: MEMBERS_LIST, - variables: { - id: '111', - }, - }, - result: { - data: { - organizations: [ - { - _id: '111', - members: [ - { - createdAt: '2023-04-13T04:53:17.742Z', - email: 'testuser4@example.com', - firstName: 'Teresa', - image: null, - lastName: 'Bradley', - organizationsBlockedBy: [], - __typename: 'User', - _id: '658930fd2caa9d8d6908745c', - }, - { - createdAt: '2024-04-13T04:53:17.742Z', - email: 'testuser2@example.com', - firstName: 'Anna', - image: null, - lastName: 'Bradley', - organizationsBlockedBy: [], - __typename: 'User', - _id: '658930fd2caa9d8d690sfhgush', - }, - ], - }, - ], - }, - }, - }, - { - request: { - query: ACTION_ITEM_LIST_BY_EVENTS, - variables: { - eventId: '123', - }, - }, - result: { - data: { - actionItemsByEvent: [ - { - _id: '_6613ef741677gygwuyu', - actionItemCategory: { - __typename: 'ActionItemCategory', - _id: '65f069a53b63ad266db32b3j', - name: 'Default', - }, - assignee: { - __typename: 'User', - _id: '6589387e2caa9d8d69087485', - firstName: 'Burton', - lastName: 'Sanders', - }, - assigner: { - __typename: 'User', - _id: '64378abd85008f171cf2990d', - firstName: 'Wilt', - lastName: 'Shepherd', - }, - assignmentDate: '2024-04-08', - completionDate: '2024-04-08', - creator: { - __typename: 'User', - _id: '64378abd85008f171cf2990d', - firstName: 'Wilt', - lastName: 'Shepherd', - }, - dueDate: '2024-04-08', - event: { - __typename: 'Event', - _id: '123', - title: 'Adult Painting Lessons', - }, - isCompleted: false, - postCompletionNotes: 'Post Completion Note', - preCompletionNotes: 'Pre Completion Note', - }, - ], - }, - refetch: jest.fn(), - }, - }, -]; - -const CREATE_ACTION_ITEM_ERROR_MOCK = [ - { - request: { - query: CREATE_ACTION_ITEM_MUTATION, - variables: { - assigneeId: '658930fd2caa9d8d6908745c', - actionItemCategoryId: '65f069a53b63ad266db32b3f', - eventId: '123', - preCompletionNotes: 'task to be done with high priority', - dueDate: '2024-04-05', - }, - }, - result: { - data: { - createActionItem: { - _id: undefined, - }, - }, - }, - }, -]; - -const UPDATE_ACTION_ITEM_ERROR_MOCK = [ - { - request: { - query: ACTION_ITEM_LIST_BY_EVENTS, - variables: { - eventId: '123', - }, - }, - result: { - data: { - actionItemsByEvent: [ - { - _id: '_6613ef741677gygwuyu', - actionItemCategory: { - __typename: 'ActionItemCategory', - _id: '65f069a53b63ad266db32b3j', - name: 'Default', - }, - assignee: { - __typename: 'User', - _id: '6589387e2caa9d8d69087485', - firstName: 'Burton', - lastName: 'Sanders', - }, - assigner: { - __typename: 'User', - _id: '64378abd85008f171cf2990d', - firstName: 'Wilt', - lastName: 'Shepherd', - }, - assignmentDate: '2024-04-08', - completionDate: '2024-04-08', - creator: { - __typename: 'User', - _id: '64378abd85008f171cf2990d', - firstName: 'Wilt', - lastName: 'Shepherd', - }, - dueDate: '2024-04-08', - event: { - __typename: 'Event', - _id: '123', - title: 'Adult Painting Lessons', - }, - isCompleted: false, - postCompletionNotes: 'Post Completion Note', - preCompletionNotes: 'Pre Completion Note', - }, - ], - }, - refetch: jest.fn(), - }, - }, - { - request: { - query: UPDATE_ACTION_ITEM_MUTATION, - variables: { - actionItemId: '_6613ef741677gygwuyu', - assigneeId: '658930fd2caa9d8d6908745c', - preCompletionNotes: 'task to be done with high priority', - postCompletionNotes: 'Done', - dueDate: '2024-04-05', - completionDate: '2024-04-05', - isCompleted: false, - }, - }, - result: { - data: { - updateActionItem: { - _id: undefined, - __typename: 'ActionItem', - }, - }, - }, - }, -]; - -const NO_ACTION_ITEMs_ERROR_MOCK = [ - { - request: { - query: ACTION_ITEM_LIST_BY_EVENTS, - variables: { - eventId: '123', - }, - }, - result: { - data: { - actionItemsByEvent: [], - }, - refetch: jest.fn(), - }, - }, -]; - -const link = new StaticMockLink(MOCKS, true); -const link2 = new StaticMockLink(CREATE_ACTION_ITEM_ERROR_MOCK, true); -const link3 = new StaticMockLink(UPDATE_ACTION_ITEM_ERROR_MOCK, true); -const link4 = new StaticMockLink(NO_ACTION_ITEMs_ERROR_MOCK, true); - -const translations = JSON.parse( - JSON.stringify( - i18nForTest.getDataByLanguage('en')?.translation.eventActionItems, - ), -); - -describe('Event Action Items Page', () => { - test('Testing add new action item modal', async () => { - window.location.assign('/event/111/123'); - render( - - - - - - {} - - - - - , - ); - await wait(); - userEvent.click(screen.getByTestId('createEventActionItemBtn')); - - await wait(); - expect(screen.getByText('Action Item Details')).toBeInTheDocument(); - - const categoryDropdown = screen.getByTestId('formSelectActionItemCategory'); - userEvent.selectOptions(categoryDropdown, 'Default'); - - expect(categoryDropdown).toHaveValue('65f069a53b63ad266db32b3f'); - - const assigneeDropdown = screen.getByTestId('formSelectAssignee'); - userEvent.selectOptions(assigneeDropdown, 'Teresa Bradley'); - - expect(assigneeDropdown).toHaveValue('658930fd2caa9d8d6908745c'); - - fireEvent.change(screen.getByPlaceholderText('Notes'), { - target: { value: 'task to be done with high priority' }, - }); - expect(screen.getByPlaceholderText('Notes')).toHaveValue( - 'task to be done with high priority', - ); - - fireEvent.change(screen.getByLabelText('Due Date'), { - target: { value: '04/05/2024' }, - }); - expect(screen.getByLabelText('Due Date')).toHaveValue('04/05/2024'); - - userEvent.click(screen.getByTestId('createActionItemFormSubmitBtn')); - - await wait(); - - expect(toast.success).toBeCalledWith(translations.successfulCreation); - }); - - test('Display all the action items', async () => { - window.location.assign('/event/111/123'); - render( - - - - - - {} - - - - - , - ); - await wait(); - - expect(screen.getByText('#')).toBeInTheDocument(); - expect(screen.getByText('Assignee')).toBeInTheDocument(); - expect(screen.getByText('Action Item Category')).toBeInTheDocument(); - expect(screen.getByText('Notes')).toBeInTheDocument(); - expect(screen.getByText('Completion Notes')).toBeInTheDocument(); - - await wait(); - expect(screen.getByText('Burton Sanders')).toBeInTheDocument(); - expect(screen.getByText('Pre Completion Note')).toBeInTheDocument(); - const updateButtons = screen.getAllByText(/Manage Actions/i); - expect(updateButtons[0]).toBeInTheDocument(); - }); - - test('Testing update action item modal', async () => { - window.location.assign('/event/111/123'); - render( - - - - - - {} - - - - - , - ); - await wait(); - const updateButtons = screen.getAllByText(/Manage Actions/i); - userEvent.click(updateButtons[0]); - - expect(screen.getByText('Action Item Details')).toBeInTheDocument(); - - const assigneeDropdown = screen.getByTestId('formUpdateAssignee'); - userEvent.selectOptions(assigneeDropdown, 'Teresa Bradley'); - - expect(assigneeDropdown).toHaveValue('658930fd2caa9d8d6908745c'); - fireEvent.change(screen.getByPlaceholderText('Notes'), { - target: { value: 'task to be done with high priority' }, - }); - expect(screen.getByPlaceholderText('Notes')).toHaveValue( - 'task to be done with high priority', - ); - - fireEvent.change(screen.getByPlaceholderText('Post Completion Notes'), { - target: { value: 'Done' }, - }); - expect(screen.getByPlaceholderText('Post Completion Notes')).toHaveValue( - 'Done', - ); - - fireEvent.change(screen.getByLabelText('Due Date'), { - target: { value: '04/05/2024' }, - }); - expect(screen.getByLabelText('Due Date')).toHaveValue('04/05/2024'); - - fireEvent.change(screen.getByLabelText('Completion Date'), { - target: { value: '04/05/2024' }, - }); - expect(screen.getByLabelText('Completion Date')).toHaveValue('04/05/2024'); - - userEvent.click(screen.getByTestId('updateActionItemFormSubmitBtn')); - - await wait(); - - expect(toast.success).toBeCalledWith(translations.successfulUpdation); - }); - test('Testing delete action item modal and delete the record', async () => { - window.location.assign('/event/111/123'); - render( - - - - - - {} - - - - - , - ); - await wait(); - const updateButtons = screen.getAllByText(/Manage Actions/i); - userEvent.click(updateButtons[0]); - - expect(screen.getByText('Action Item Details')).toBeInTheDocument(); - - expect(screen.getByTestId('deleteActionItemBtn')).toBeInTheDocument(); - userEvent.click(screen.getByTestId('deleteActionItemBtn')); - await wait(); - expect( - screen.getByText('Do you want to remove this action item?'), - ).toBeInTheDocument(); - userEvent.click(screen.getByText('Yes')); - await wait(); - - expect(toast.success).toBeCalledWith(translations.successfulDeletion); - }); - - test('Testing delete action item modal and does not delete the record', async () => { - window.location.assign('/event/111/123'); - render( - - - - - - {} - - - - - , - ); - await wait(); - const updateButtons = screen.getAllByText(/Manage Actions/i); - userEvent.click(updateButtons[0]); - - expect(screen.getByText('Action Item Details')).toBeInTheDocument(); - - expect(screen.getByTestId('deleteActionItemBtn')).toBeInTheDocument(); - userEvent.click(screen.getByTestId('deleteActionItemBtn')); - await wait(); - expect( - screen.getByText('Do you want to remove this action item?'), - ).toBeInTheDocument(); - userEvent.click(screen.getByText('No')); - await wait(); - expect(screen.getByText('Teresa Bradley')).toBeInTheDocument(); - }); - - test('Raises an error when incorrect information is filled while creation', async () => { - window.location.assign('/event/111/123'); - render( - - - - - - {} - - - - - , - ); - await wait(); - userEvent.click(screen.getByTestId('createEventActionItemBtn')); - - await wait(); - expect(screen.getByText('Action Item Details')).toBeInTheDocument(); - - fireEvent.change(screen.getByPlaceholderText('Notes'), { - target: { value: 'task to be done with high priority' }, - }); - expect(screen.getByPlaceholderText('Notes')).toHaveValue( - 'task to be done with high priority', - ); - - fireEvent.change(screen.getByLabelText('Due Date'), { - target: { value: '04/05/2024' }, - }); - expect(screen.getByLabelText('Due Date')).toHaveValue('04/05/2024'); - - userEvent.click(screen.getByTestId('createActionItemFormSubmitBtn')); - await wait(); - - expect(toast.error).toBeCalled(); - }); - - test('Raises an error when incorrect information is filled while updation', async () => { - window.location.assign('/event/111/123'); - render( - - - - - - {} - - - - - , - ); - await wait(); - const updateButtons = screen.getAllByText(/Manage Actions/i); - userEvent.click(updateButtons[0]); - - expect(screen.getByText('Action Item Details')).toBeInTheDocument(); - - userEvent.click(screen.getByTestId('updateActionItemFormSubmitBtn')); - - await wait(); - - expect(toast.success).toBeCalledWith(translations.successfulUpdation); - - expect(toast.error).toBeCalled(); - }); - - test('Displays message when no data is available', async () => { - window.location.assign('/event/111/123'); - render( - - - - - - {} - - - - - , - ); - await wait(); - expect(screen.getByText('Nothing Found !!')).toBeInTheDocument(); - }); -}); diff --git a/src/components/EventManagement/EventActionItems/EventActionItems.tsx b/src/components/EventManagement/EventActionItems/EventActionItems.tsx deleted file mode 100644 index 717269b3ce..0000000000 --- a/src/components/EventManagement/EventActionItems/EventActionItems.tsx +++ /dev/null @@ -1,599 +0,0 @@ -import { useMutation, useQuery } from '@apollo/client'; -import type { Dayjs } from 'dayjs'; -import dayjs from 'dayjs'; -import type { ChangeEvent } from 'react'; -import React, { useEffect, useState } from 'react'; -import { Button, Form } from 'react-bootstrap'; -import { useTranslation } from 'react-i18next'; -import { Link } from 'react-router-dom'; -import { toast } from 'react-toastify'; -import styles from './EventActionItems.module.css'; -import { DataGrid } from '@mui/x-data-grid'; -import type { GridColDef, GridCellParams } from '@mui/x-data-grid'; -import { Stack } from '@mui/material'; -import Modal from 'react-bootstrap/Modal'; -import { - CREATE_ACTION_ITEM_MUTATION, - DELETE_ACTION_ITEM_MUTATION, - UPDATE_ACTION_ITEM_MUTATION, -} from 'GraphQl/Mutations/ActionItemMutations'; -import type { - InterfaceActionItemCategoryList, - InterfaceMembersList, -} from 'utils/interfaces'; -import { DatePicker } from '@mui/x-date-pickers'; -import { - ACTION_ITEM_CATEGORY_LIST, - MEMBERS_LIST, -} from 'GraphQl/Queries/Queries'; -import { ACTION_ITEM_LIST_BY_EVENTS } from 'GraphQl/Queries/ActionItemQueries'; - -function eventActionItems(props: { eventId: string }): JSX.Element { - const { eventId } = props; - const { t } = useTranslation('translation', { - keyPrefix: 'eventActionItems', - }); - const { t: tCommon } = useTranslation('common'); - - const [actionItemCreateModalIsOpen, setActionItemCreateModalIsOpen] = - useState(false); - const [actionItemUpdateModalIsOpen, setActionItemUpdateModalIsOpen] = - useState(false); - const [actionItemDeleteModalIsOpen, setActionItemDeleteModalIsOpen] = - useState(false); - const [dueDate, setDueDate] = useState(new Date()); - const [completionDate, setCompletionDate] = useState(new Date()); - const [actionItemId, setActionItemId] = useState(''); - document.title = t('title'); - const url: string = window.location.href; - const startIdx: number = url.indexOf('/event/') + '/event/'.length; - const orgId: string = url.slice(startIdx, url.indexOf('/', startIdx)); - const [formState, setFormState] = useState({ - actionItemCategoryId: '', - assignee: '', - assigner: '', - assigneeId: '', - preCompletionNotes: '', - postCompletionNotes: '', - isCompleted: false, - }); - const showCreateModal = (): void => { - const newState = !actionItemCreateModalIsOpen; - setActionItemCreateModalIsOpen(newState); - }; - const hideCreateModal = (): void => { - setActionItemCreateModalIsOpen(!actionItemCreateModalIsOpen); - }; - const showUpdateModal = (): void => { - setActionItemUpdateModalIsOpen(!actionItemUpdateModalIsOpen); - }; - const hideUpdateModal = (): void => { - setActionItemId(''); - setActionItemUpdateModalIsOpen(!actionItemUpdateModalIsOpen); - }; - const toggleDeleteModal = (): void => { - setActionItemDeleteModalIsOpen(!actionItemDeleteModalIsOpen); - }; - const { - data: actionItemCategoriesData, - }: { - data: InterfaceActionItemCategoryList | undefined; - loading: boolean; - error?: Error | undefined; - } = useQuery(ACTION_ITEM_CATEGORY_LIST, { - variables: { - organizationId: orgId, - }, - }); - const actionItemCategories = - actionItemCategoriesData?.actionItemCategoriesByOrganization.filter( - (category) => !category.isDisabled, - ); - const { data: actionItemsData, refetch: actionItemsRefetch } = useQuery( - ACTION_ITEM_LIST_BY_EVENTS, - { - variables: { - eventId, - }, - }, - ); - const { - data: membersData, - }: { - data: InterfaceMembersList | undefined; - loading: boolean; - error?: Error | undefined; - } = useQuery(MEMBERS_LIST, { - variables: { id: orgId }, - }); - const [createActionItem] = useMutation(CREATE_ACTION_ITEM_MUTATION); - const createActionItemHandler = async ( - e: ChangeEvent, - ): Promise => { - e.preventDefault(); - try { - await createActionItem({ - variables: { - assigneeId: formState.assigneeId, - actionItemCategoryId: formState.actionItemCategoryId, - eventId, - preCompletionNotes: formState.preCompletionNotes, - dueDate: dayjs(dueDate).format('YYYY-MM-DD'), - }, - }); - setFormState({ - actionItemCategoryId: '', - assignee: '', - assigner: '', - assigneeId: '', - preCompletionNotes: '', - postCompletionNotes: '', - isCompleted: false, - }); - setDueDate(new Date()); - actionItemsRefetch(); - hideCreateModal(); - toast.success(t('successfulCreation')); - } catch (error: unknown) { - if (error instanceof Error) { - toast.error(error.message); - } - } - }; - useEffect(() => { - actionItemsRefetch({ - eventId, - }); - }, []); - const [updateActionItem] = useMutation(UPDATE_ACTION_ITEM_MUTATION); - const updateActionItemHandler = async ( - e: ChangeEvent, - ): Promise => { - e.preventDefault(); - try { - await updateActionItem({ - variables: { - actionItemId, - assigneeId: formState.assigneeId, - preCompletionNotes: formState.preCompletionNotes, - postCompletionNotes: formState.postCompletionNotes, - dueDate: dayjs(dueDate).format('YYYY-MM-DD'), - completionDate: dayjs(completionDate).format('YYYY-MM-DD'), - isCompleted: formState.isCompleted, - }, - }); - actionItemsRefetch(); - hideUpdateModal(); - toast.success(t('successfulUpdation')); - } catch (error: unknown) { - if (error instanceof Error) { - toast.error(error.message); - } - } - }; - const [removeActionItem] = useMutation(DELETE_ACTION_ITEM_MUTATION); - const deleteActionItemHandler = async (): Promise => { - await removeActionItem({ - variables: { - actionItemId, - }, - }); - actionItemsRefetch(); - toggleDeleteModal(); - hideUpdateModal(); - toast.success(t('successfulDeletion')); - }; - const columns: GridColDef[] = [ - { - field: 'serialNo', - headerName: '#', - flex: 1, - minWidth: 50, - align: 'center', - headerAlign: 'center', - headerClassName: `${styles.tableHeader}`, - sortable: false, - renderCell: (params: GridCellParams) => { - return params.row?.index; - }, - }, - { - field: 'assignee', - headerName: 'Assignee', - flex: 2, - minWidth: 150, - align: 'center', - headerAlign: 'center', - headerClassName: `${styles.tableHeader}`, - sortable: false, - renderCell: (params: GridCellParams) => { - return ( - - {params.row?.assignee.firstName + - ' ' + - params.row?.assignee.lastName} - - ); - }, - }, - { - field: 'actionItemCategory', - headerName: 'Action Item Category', - flex: 2, - minWidth: 100, - align: 'center', - headerAlign: 'center', - headerClassName: `${styles.tableHeader}`, - sortable: false, - renderCell: (params: GridCellParams) => { - return params.row.actionItemCategory.name; - }, - }, - { - field: 'notes', - headerName: 'Notes', - minWidth: 150, - align: 'center', - headerAlign: 'center', - headerClassName: `${styles.tableHeader}`, - flex: 2, - sortable: false, - renderCell: (params: GridCellParams) => { - return params.row.preCompletionNotes; - }, - }, - { - field: 'completionNotes', - headerName: 'Completion Notes', - minWidth: 150, - align: 'center', - headerAlign: 'center', - headerClassName: `${styles.tableHeader}`, - flex: 2, - sortable: false, - renderCell: (params: GridCellParams) => { - return params.row.postCompletionNotes; - }, - }, - { - field: 'options', - headerName: 'Options', - flex: 2, - minWidth: 100, - align: 'center', - headerAlign: 'center', - headerClassName: `${styles.tableHeader}`, - sortable: false, - renderCell: (params: GridCellParams) => { - return ( - - ); - }, - }, - ]; - return ( - <> - - {/* create action item modal */} - - -

    {t('actionItemDetails')}

    - -
    - -
    - - {t('actionItemCategory')} - - setFormState({ - ...formState, - actionItemCategoryId: e.target.value, - }) - } - > - - {actionItemCategories?.map((category, index) => ( - - ))} - - - - {t('assignee')} - - setFormState({ ...formState, assigneeId: e.target.value }) - } - > - - {membersData?.organizations[0].members?.map((member, index) => ( - - ))} - - - - { - setFormState({ - ...formState, - preCompletionNotes: e.target.value, - }); - }} - /> -
    - { - if (date) { - setDueDate(date?.toDate()); - } - }} - /> -
    - - -
    -
    - {/* update action items modal */} - - -

    {t('actionItemDetails')}

    - -
    - -
    - - Assignee - - setFormState({ ...formState, assigneeId: e.target.value }) - } - > - - {membersData?.organizations[0].members.map((member, index) => { - const currMemberName = `${member.firstName} ${member.lastName}`; - if (currMemberName !== formState.assignee) { - return ( - - ); - } - })} - - - - { - setFormState({ - ...formState, - preCompletionNotes: e.target.value, - }); - }} - /> - - { - setFormState({ - ...formState, - postCompletionNotes: e.target.value, - }); - }} - className="mb-2" - /> -

    -
    - { - if (date) { - setDueDate(date?.toDate()); - } - }} - /> -   - { - if (date) { - setCompletionDate(date?.toDate()); - } - }} - /> -
    -

    -
    - - - -
    - -
    -
    - {/* delete modal */} - - - - {t('deleteActionItem')} - - - {t('deleteActionItemMsg')} - - - - - - {actionItemsData && ( -
    - row._id} - components={{ - NoRowsOverlay: () => ( - - Nothing Found !! - - ), - }} - sx={{ - '&.MuiDataGrid-root .MuiDataGrid-cell:focus-within': { - outline: 'none !important', - }, - '&.MuiDataGrid-root .MuiDataGrid-columnHeader:focus-within': { - outline: 'none', - }, - '& .MuiDataGrid-row:hover': { - backgroundColor: 'transparent', - }, - '& .MuiDataGrid-row.Mui-hovered': { - backgroundColor: 'transparent', - }, - }} - getRowClassName={() => `${styles.rowBackground}`} - autoHeight - rowHeight={70} - rows={actionItemsData?.actionItemsByEvent?.map( - (item: object, index: number) => ({ - ...item, - index: index + 1, - }), - )} - columns={columns} - isRowSelectable={() => false} - /> -
    - )} - - ); -} -export default eventActionItems; diff --git a/src/components/EventManagement/EventAgendaItems/EventAgendaItems.module.css b/src/components/EventManagement/EventAgendaItems/EventAgendaItems.module.css new file mode 100644 index 0000000000..9d1c32b766 --- /dev/null +++ b/src/components/EventManagement/EventAgendaItems/EventAgendaItems.module.css @@ -0,0 +1,22 @@ +.eventAgendaItemContainer h2 { + margin: 0.6rem 0; +} + +.btnsContainer { + display: flex; + gap: 10px; +} + +@media (max-width: 768px) { + .btnsContainer { + margin-bottom: 0; + display: flex; + flex-direction: column; + } + + .createAgendaItemButton { + position: absolute; + top: 1rem; + right: 2rem; + } +} diff --git a/src/components/EventManagement/EventAgendaItems/EventAgendaItems.test.tsx b/src/components/EventManagement/EventAgendaItems/EventAgendaItems.test.tsx new file mode 100644 index 0000000000..3bce7ad11e --- /dev/null +++ b/src/components/EventManagement/EventAgendaItems/EventAgendaItems.test.tsx @@ -0,0 +1,214 @@ +import React from 'react'; +import { + render, + screen, + waitFor, + act, + waitForElementToBeRemoved, +} from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import 'jest-localstorage-mock'; +import { MockedProvider } from '@apollo/client/testing'; +import 'jest-location-mock'; +import { I18nextProvider } from 'react-i18next'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; +import i18n from 'utils/i18nForTest'; +// import { toast } from 'react-toastify'; +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; + +import { store } from 'state/store'; +import { StaticMockLink } from 'utils/StaticMockLink'; + +import EventAgendaItems from './EventAgendaItems'; + +import { + MOCKS, + MOCKS_ERROR_QUERY, + // MOCKS_ERROR_MUTATION, +} from './EventAgendaItemsMocks'; + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + error: jest.fn(), + }, +})); + +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ eventId: '123' }), +})); + +//temporarily fixes react-beautiful-dnd droppable method's depreciation error +//needs to be fixed in React 19 +jest.spyOn(console, 'error').mockImplementation((message) => { + if (message.includes('Support for defaultProps will be removed')) { + return; + } + console.error(message); +}); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +const link = new StaticMockLink(MOCKS, true); +const link2 = new StaticMockLink(MOCKS_ERROR_QUERY, true); +// const link3 = new StaticMockLink(MOCKS_ERROR_MUTATION, true); + +const translations = JSON.parse( + JSON.stringify(i18n.getDataByLanguage('en')?.translation.agendaItems), +); + +describe('Testing Agenda Items Components', () => { + const formData = { + title: 'AgendaItem 1', + description: 'AgendaItem 1 Description', + duration: '30', + relatedEventId: '123', + organizationId: '111', + sequence: 1, + categories: ['Category 1'], + attachments: [], + urls: [], + }; + test('Component loads correctly', async () => { + window.location.assign('/event/111/123'); + const { getByText } = render( + + + + + {} + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(getByText(translations.createAgendaItem)).toBeInTheDocument(); + }); + }); + + test('render error component on unsuccessful agenda item query', async () => { + window.location.assign('/event/111/123'); + const { queryByText } = render( + + + + + {} + + + + , + ); + + await wait(); + + await waitFor(() => { + expect( + queryByText(translations.createAgendaItem), + ).not.toBeInTheDocument(); + }); + }); + + test('opens and closes the create agenda item modal', async () => { + window.location.assign('/event/111/123'); + render( + + + + + + {} + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('createAgendaItemBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('createAgendaItemBtn')); + + await waitFor(() => { + return expect( + screen.findByTestId('createAgendaItemModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('createAgendaItemModalCloseBtn')); + + await waitForElementToBeRemoved(() => + screen.queryByTestId('createAgendaItemModalCloseBtn'), + ); + }); + test('creates new agenda item', async () => { + window.location.assign('/event/111/123'); + render( + + + + + + {} + + + + + , + ); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('createAgendaItemBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('createAgendaItemBtn')); + + await waitFor(() => { + expect( + screen.getByTestId('createAgendaItemModalCloseBtn'), + ).toBeInTheDocument(); + }); + + userEvent.type( + screen.getByPlaceholderText(translations.enterTitle), + formData.title, + ); + + userEvent.type( + screen.getByPlaceholderText(translations.enterDescription), + formData.description, + ); + userEvent.type( + screen.getByPlaceholderText(translations.enterDuration), + formData.duration, + ); + const categorySelect = screen.getByTestId('categorySelect'); + userEvent.click(categorySelect); + await waitFor(() => { + const categoryOption = screen.getByText('Category 1'); + userEvent.click(categoryOption); + }); + + userEvent.click(screen.getByTestId('createAgendaItemFormBtn')); + + await waitFor(() => { + // expect(toast.success).toBeCalledWith(translations.agendaItemCreated); + }); + }); +}); diff --git a/src/components/EventManagement/EventAgendaItems/EventAgendaItems.tsx b/src/components/EventManagement/EventAgendaItems/EventAgendaItems.tsx new file mode 100644 index 0000000000..b49ade4626 --- /dev/null +++ b/src/components/EventManagement/EventAgendaItems/EventAgendaItems.tsx @@ -0,0 +1,230 @@ +import React, { useState } from 'react'; +import type { ChangeEvent } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Button } from 'react-bootstrap'; + +import { WarningAmberRounded } from '@mui/icons-material'; +import { toast } from 'react-toastify'; + +import { useMutation, useQuery } from '@apollo/client'; +import { + AGENDA_ITEM_CATEGORY_LIST, + AgendaItemByEvent, +} from 'GraphQl/Queries/Queries'; +import { CREATE_AGENDA_ITEM_MUTATION } from 'GraphQl/Mutations/mutations'; + +import type { + InterfaceAgendaItemCategoryList, + InterfaceAgendaItemList, +} from 'utils/interfaces'; +import AgendaItemsContainer from 'components/AgendaItems/AgendaItemsContainer'; +import AgendaItemsCreateModal from 'components/AgendaItems/AgendaItemsCreateModal'; + +import styles from './EventAgendaItems.module.css'; +import Loader from 'components/Loader/Loader'; + +/** + * Component to manage and display agenda items for a specific event. + * + * @param props - The component props. + * @param eventId - The ID of the event to manage agenda items for. + * @returns The rendered component. + */ +function EventAgendaItems(props: { eventId: string }): JSX.Element { + const { eventId } = props; + + const { t } = useTranslation('translation', { + keyPrefix: 'agendaItems', + }); + + // Extract organization ID from URL + const url: string = window.location.href; + const startIdx: number = url.indexOf('/event/') + '/event/'.length; + const orgId: string = url.slice(startIdx, url.indexOf('/', startIdx)); + + // State to manage the create agenda item modal visibility + const [agendaItemCreateModalIsOpen, setAgendaItemCreateModalIsOpen] = + useState(false); + + // State to manage form values + const [formState, setFormState] = useState({ + agendaItemCategoryIds: [''], + title: '', + description: '', + duration: '', + attachments: [''], + urls: [''], + }); + + // Query for agenda item categories + const { + data: agendaCategoryData, + loading: agendaCategoryLoading, + error: agendaCategoryError, + }: { + data: InterfaceAgendaItemCategoryList | undefined; + loading: boolean; + error?: Error | undefined; + } = useQuery(AGENDA_ITEM_CATEGORY_LIST, { + variables: { organizationId: orgId }, + notifyOnNetworkStatusChange: true, + }); + + // Query for agenda items by event + const { + data: agendaItemData, + loading: agendaItemLoading, + error: agendaItemError, + refetch: refetchAgendaItem, + }: { + data: InterfaceAgendaItemList | undefined; + loading: boolean; + error?: unknown | undefined; + refetch: () => void; + } = useQuery(AgendaItemByEvent, { + variables: { relatedEventId: eventId }, //eventId + notifyOnNetworkStatusChange: true, + }); + + // Mutation for creating an agenda item + const [createAgendaItem] = useMutation(CREATE_AGENDA_ITEM_MUTATION); + + /** + * Handler for creating a new agenda item. + * + * @param e - The form submit event. + */ + const createAgendaItemHandler = async ( + e: ChangeEvent, + ): Promise => { + e.preventDefault(); + try { + await createAgendaItem({ + variables: { + input: { + title: formState.title, + description: formState.description, + relatedEventId: eventId, + organizationId: orgId, + sequence: (agendaItemData?.agendaItemByEvent.length || 0) + 1 || 1, // Assign sequence based on current length + duration: formState.duration, + categories: formState.agendaItemCategoryIds, + attachments: formState.attachments, + urls: formState.urls, + }, + }, + }); + + // Reset form state and hide modal + setFormState({ + title: '', + description: '', + duration: '', + agendaItemCategoryIds: [''], + attachments: [''], + urls: [''], + }); + hideCreateModal(); + refetchAgendaItem(); + toast.success(t('agendaItemCreated') as string); + } catch (error: unknown) { + if (error instanceof Error) { + toast.error(error.message); + } + } + }; + + /** + * Toggles the visibility of the create agenda item modal. + */ + const showCreateModal = (): void => { + setAgendaItemCreateModalIsOpen(!agendaItemCreateModalIsOpen); + }; + + /** + * Hides the create agenda item modal. + */ + const hideCreateModal = (): void => { + setAgendaItemCreateModalIsOpen(!agendaItemCreateModalIsOpen); + }; + + // Show loader while data is loading + if (agendaItemLoading || agendaCategoryLoading) return ; + + // Show error message if there is an error loading data + if (agendaItemError || agendaCategoryError) { + const errorMessage = + agendaCategoryError?.message || + (agendaItemError as Error)?.message || + 'Unknown error'; + + return ( +
    +
    + +
    + Error occurred while loading{' '} + {agendaCategoryError ? 'Agenda Categories' : 'Agenda Items'} Data +
    + {errorMessage} +
    +
    +
    + ); + } + + return ( +
    +
    +
    +
    +
    + {/* setSearchValue(e.target.value)} + value={searchValue} + data-testid="search" + /> */} +
    + + +
    +
    + +
    + + +
    + + +
    + ); +} + +export default EventAgendaItems; diff --git a/src/components/EventManagement/EventAgendaItems/EventAgendaItemsMocks.ts b/src/components/EventManagement/EventAgendaItems/EventAgendaItemsMocks.ts new file mode 100644 index 0000000000..619a1e70f8 --- /dev/null +++ b/src/components/EventManagement/EventAgendaItems/EventAgendaItemsMocks.ts @@ -0,0 +1,133 @@ +import { CREATE_AGENDA_ITEM_MUTATION } from 'GraphQl/Mutations/AgendaItemMutations'; + +import { AgendaItemByEvent } from 'GraphQl/Queries/AgendaItemQueries'; +import { AGENDA_ITEM_CATEGORY_LIST } from 'GraphQl/Queries/AgendaCategoryQueries'; + +export const MOCKS = [ + { + request: { + query: AGENDA_ITEM_CATEGORY_LIST, + variables: { organizationId: '111' }, + }, + result: { + data: { + agendaItemCategoriesByOrganization: [ + { + _id: 'agendaItemCategory1', + name: 'Category 1', + description: 'Test Description', + createdBy: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + }, + ], + }, + }, + }, + { + request: { + query: AgendaItemByEvent, + variables: { relatedEventId: '123' }, + }, + result: { + data: { + agendaItemByEvent: [ + { + _id: 'agendaItem1', + title: 'AgendaItem 1', + description: 'AgendaItem 1 Description', + duration: '30', + attachments: [], + createdBy: { + _id: 'user0', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + urls: [], + users: [], + sequence: 1, + categories: [ + { + _id: 'agendaItemCategory1', + name: 'Category 1', + }, + ], + organization: { + _id: '111', + name: 'Unity Foundation', + }, + relatedEvent: { + _id: '123', + title: 'Aerobics for Everyone', + }, + }, + ], + }, + }, + }, + { + request: { + query: CREATE_AGENDA_ITEM_MUTATION, + variables: { + input: { + title: 'AgendaItem 1', + description: 'AgendaItem 1 Description', + duration: '30', + relatedEventId: '123', + organizationId: '111', + sequence: 1, + categories: ['Category 1'], + attachments: [], + urls: [], + }, + }, + }, + result: { + data: { + createAgendaItem: { + _id: 'agendaItem1', + }, + }, + }, + }, +]; + +export const MOCKS_ERROR_MUTATION = [ + { + request: { + query: CREATE_AGENDA_ITEM_MUTATION, + variables: { + input: { + title: 'AgendaItem 1', + description: 'AgendaItem 1 Description', + duration: '30', + relatedEventId: '123', + organizationId: '111', + sequence: 1, + categories: ['agendaItemCategory1'], + attachments: [], + urls: [], + }, + }, + }, + error: new Error('Mock Graphql Error'), + }, + { + request: { + query: AgendaItemByEvent, + variables: { relatedEventId: '123' }, + }, + error: new Error('Mock Graphql Error'), + }, + { + request: { + query: AGENDA_ITEM_CATEGORY_LIST, + variables: { organizationId: '111' }, + }, + error: new Error('Mock Graphql Error'), + }, +]; + +export const MOCKS_ERROR_QUERY = []; diff --git a/src/components/EventRegistrantsModal/EventRegistrantsModal.test.tsx b/src/components/EventRegistrantsModal/EventRegistrantsModal.test.tsx index 597502ac8e..8a084fef24 100644 --- a/src/components/EventRegistrantsModal/EventRegistrantsModal.test.tsx +++ b/src/components/EventRegistrantsModal/EventRegistrantsModal.test.tsx @@ -194,9 +194,7 @@ describe('Testing Event Registrants Modal', () => { ); await waitFor(() => - expect( - queryByText('Added the attendee successfully!'), - ).toBeInTheDocument(), + expect(queryByText('Attendee added Successfully')).toBeInTheDocument(), ); }); @@ -244,9 +242,7 @@ describe('Testing Event Registrants Modal', () => { ); await waitFor(() => - expect( - queryByText('There was an error in adding the attendee!'), - ).toBeInTheDocument(), + expect(queryByText('Error adding attendee')).toBeInTheDocument(), ); }); @@ -286,9 +282,7 @@ describe('Testing Event Registrants Modal', () => { ); await waitFor(() => - expect( - queryByText('Removed the attendee successfully!'), - ).toBeInTheDocument(), + expect(queryByText('Attendee removed Successfully')).toBeInTheDocument(), ); }); @@ -328,9 +322,7 @@ describe('Testing Event Registrants Modal', () => { ); await waitFor(() => - expect( - queryByText('There was an error in removing the attendee!'), - ).toBeInTheDocument(), + expect(queryByText('Error removing attendee')).toBeInTheDocument(), ); }); }); diff --git a/src/components/EventRegistrantsModal/EventRegistrantsModal.tsx b/src/components/EventRegistrantsModal/EventRegistrantsModal.tsx index 2ac3f7490e..762fd4c280 100644 --- a/src/components/EventRegistrantsModal/EventRegistrantsModal.tsx +++ b/src/components/EventRegistrantsModal/EventRegistrantsModal.tsx @@ -14,7 +14,10 @@ import Stack from '@mui/material/Stack'; import TextField from '@mui/material/TextField'; import Autocomplete from '@mui/material/Autocomplete'; import AddOnSpotAttendee from './AddOnSpotAttendee'; +import { useTranslation } from 'react-i18next'; + +// Props for the EventRegistrantsModal component type ModalPropType = { show: boolean; eventId: string; @@ -22,18 +25,24 @@ type ModalPropType = { handleClose: () => void; }; +// User information interface interface InterfaceUser { _id: string; firstName: string; lastName: string; } - -export const EventRegistrantsModal = ({ - show, - eventId, - orgId, - handleClose, -}: ModalPropType): JSX.Element => { +/** + * Modal component for managing event registrants. + * Allows adding and removing attendees from an event. + * + * @param show - Whether the modal is visible or not. + * @param eventId - The ID of the event. + * @param orgId - The ID of the organization. + * @param handleClose - Function to close the modal. + * @returns JSX element representing the modal. + */ +export const EventRegistrantsModal = (props: ModalPropType): JSX.Element => { + const { eventId, orgId, handleClose, show } = props; const [member, setMember] = useState(null); const [isAdding, setIsAdding] = useState(false); const [addRegistrantMutation] = useMutation(ADD_EVENT_ATTENDEE, { @@ -44,8 +53,17 @@ export const EventRegistrantsModal = ({ }); const [open, setOpen] = useState(false); + // Hooks for mutation operations + const [addRegistrantMutation] = useMutation(ADD_EVENT_ATTENDEE); const [removeRegistrantMutation] = useMutation(REMOVE_EVENT_ATTENDEE); + // Translation hooks + const { t } = useTranslation('translation', { + keyPrefix: 'eventRegistrantsModal', + }); + const { t: tCommon } = useTranslation('common'); + + // Query hooks to fetch event attendees and organization members const { data: attendeesData, loading: attendeesLoading, @@ -63,6 +81,7 @@ export const EventRegistrantsModal = ({ pollInterval: 500, }); + // Function to add a new registrant to the event const addRegistrant = (): void => { if (member == null) { toast.warning('Please choose a user to add first!'); @@ -77,11 +96,13 @@ export const EventRegistrantsModal = ({ }, }) .then(() => { - toast.success('Added the attendee successfully!'); - attendeesRefetch(); + toast.success( + tCommon('addedSuccessfully', { item: 'Attendee' }) as string, + ); + attendeesRefetch(); // Refresh the list of attendees }) .catch((err) => { - toast.error('There was an error in adding the attendee!'); + toast.error(t('errorAddingAttendee') as string); toast.error(err.message); }) .finally(() => { @@ -89,6 +110,7 @@ export const EventRegistrantsModal = ({ }); }; + // Function to remove a registrant from the event const deleteRegistrant = (userId: string): void => { toast.warn('Removing the attendee...'); removeRegistrantMutation({ @@ -98,11 +120,13 @@ export const EventRegistrantsModal = ({ }, }) .then(() => { - toast.success('Removed the attendee successfully!'); - attendeesRefetch(); + toast.success( + tCommon('removedSuccessfully', { item: 'Attendee' }) as string, + ); + attendeesRefetch(); // Refresh the list of attendees }) .catch((err) => { - toast.error('There was an error in removing the attendee!'); + toast.error(t('errorRemovingAttendee') as string); toast.error(err.message); }); }; @@ -118,7 +142,6 @@ export const EventRegistrantsModal = ({ } }, [show, attendeesRefetch, memberRefetch]); - // Render the loading screen if (attendeesLoading || memberLoading) { return ( <> diff --git a/src/components/EventRegistrantsModal/EventRegistrantsWrapper.tsx b/src/components/EventRegistrantsModal/EventRegistrantsWrapper.tsx index 53ba82d4fa..b198fcdd6d 100644 --- a/src/components/EventRegistrantsModal/EventRegistrantsWrapper.tsx +++ b/src/components/EventRegistrantsModal/EventRegistrantsWrapper.tsx @@ -4,25 +4,35 @@ import { Button } from 'react-bootstrap'; import IconComponent from 'components/IconComponent/IconComponent'; import styles from './EventRegistrantsWrapper.module.css'; +// Props for the EventRegistrantsWrapper component type PropType = { eventId: string; orgId: string; }; -export const EventRegistrantsWrapper: React.FC = ({ +/** + * Wrapper component that displays a button to show the event registrants modal. + * + * @param eventId - The ID of the event. + * @param orgId - The ID of the organization. + * @returns JSX element representing the wrapper with a button to show the modal. + */ +export const EventRegistrantsWrapper = ({ eventId, orgId, -}) => { +}: PropType): JSX.Element => { + // State to control the visibility of the modal const [showModal, setShowModal] = useState(false); return ( <> + {/* Button to open the event registrants modal */} + {/* Render the EventRegistrantsModal if showModal is true */} {showModal && ( { - setShowModal(false); + setShowModal(false); // Hide the modal when closed }} eventId={eventId} orgId={orgId} diff --git a/src/components/EventStats/EventStats.tsx b/src/components/EventStats/EventStats.tsx index c9f1a70e8d..ce1e55e4bc 100644 --- a/src/components/EventStats/EventStats.tsx +++ b/src/components/EventStats/EventStats.tsx @@ -8,22 +8,33 @@ import eventStatsStyles from './EventStats.module.css'; import { useQuery } from '@apollo/client'; import { EVENT_FEEDBACKS } from 'GraphQl/Queries/Queries'; +// Props for the EventStats component type ModalPropType = { show: boolean; eventId: string; handleClose: () => void; }; +/** + * Component that displays event statistics in a modal. + * Shows feedback, reviews, and average rating for the event. + * + * @param show - Whether the modal is visible or not. + * @param handleClose - Function to close the modal. + * @param eventId - The ID of the event. + * @returns JSX element representing the event statistics modal. + */ export const EventStats = ({ show, handleClose, eventId, }: ModalPropType): JSX.Element => { + // Query to fetch event feedback data const { data, loading } = useQuery(EVENT_FEEDBACKS, { variables: { id: eventId }, }); - // Render the loading screen + // Show a loading screen while data is being fetched if (loading) { return ( <> @@ -36,7 +47,7 @@ export const EventStats = ({ <> Event Statistics + {/* Render feedback statistics */}
    + {/* Render review statistics and average rating */}
    diff --git a/src/components/EventStats/EventStatsWrapper.tsx b/src/components/EventStats/EventStatsWrapper.tsx index b501e77430..fb701a00da 100644 --- a/src/components/EventStats/EventStatsWrapper.tsx +++ b/src/components/EventStats/EventStatsWrapper.tsx @@ -4,21 +4,30 @@ import { Button } from 'react-bootstrap'; import IconComponent from 'components/IconComponent/IconComponent'; import styles from './EventStatsWrapper.module.css'; +// Props for the EventStatsWrapper component type PropType = { eventId: string; }; -export const EventStatsWrapper = (props: PropType): JSX.Element => { +/** + * Wrapper component that displays a button to show event statistics. + * + * @param eventId - The ID of the event. + * @returns JSX element representing the wrapper with a button to view event statistics. + */ +export const EventStatsWrapper = ({ eventId }: PropType): JSX.Element => { + // State to control the visibility of the EventStats component const [showModal, setShowModal] = useState(false); return ( <> + {/* Button to open the event statistics view */} + + {/* Render the EventStats component if showModal is true */} setShowModal(false)} - key={props.eventId || 'eventStatsDetails'} - eventId={props.eventId} + handleClose={(): void => setShowModal(false)} // Hide the EventStats component when closed + key={eventId || 'eventStatsDetails'} // Use eventId as key for the component + eventId={eventId} /> ); diff --git a/src/components/EventStats/Statistics/AverageRating.tsx b/src/components/EventStats/Statistics/AverageRating.tsx index 6dcfa03b3f..9f1a157e01 100644 --- a/src/components/EventStats/Statistics/AverageRating.tsx +++ b/src/components/EventStats/Statistics/AverageRating.tsx @@ -5,6 +5,7 @@ import FavoriteIcon from '@mui/icons-material/Favorite'; import FavoriteBorderIcon from '@mui/icons-material/FavoriteBorder'; import Typography from '@mui/material/Typography'; +// Props for the AverageRating component type ModalPropType = { data: { event: { @@ -15,12 +16,20 @@ type ModalPropType = { }; }; +// Type representing individual feedback type FeedbackType = { _id: string; rating: number; review: string | null; }; +/** + * Component that displays the average rating for an event. + * Shows a rating value and a star rating icon. + * + * @param data - Data containing the average feedback score to be displayed. + * @returns JSX element representing the average rating card with a star rating. + */ export const AverageRating = ({ data }: ModalPropType): JSX.Element => { return ( <> @@ -43,10 +52,10 @@ export const AverageRating = ({ data }: ModalPropType): JSX.Element => { emptyIcon={} sx={{ '& .MuiRating-iconFilled': { - color: '#ff6d75', + color: '#ff6d75', // Color for filled stars }, '& .MuiRating-iconHover': { - color: '#ff3d47', + color: '#ff3d47', // Color for star on hover }, }} /> diff --git a/src/components/EventStats/Statistics/Feedback.tsx b/src/components/EventStats/Statistics/Feedback.tsx index a4a9e41430..a6a255828f 100644 --- a/src/components/EventStats/Statistics/Feedback.tsx +++ b/src/components/EventStats/Statistics/Feedback.tsx @@ -6,6 +6,7 @@ import { } from '@mui/x-charts/PieChart'; import Card from 'react-bootstrap/Card'; +// Props for the FeedbackStats component type ModalPropType = { data: { event: { @@ -16,13 +17,22 @@ type ModalPropType = { }; }; +// Type representing individual feedback type FeedbackType = { _id: string; rating: number; review: string | null; }; +/** + * Component that displays a pie chart of feedback ratings for an event. + * Shows how many people gave each rating. + * + * @param data - Data containing event feedback to be displayed in the chart. + * @returns JSX element representing the feedback analysis card with a pie chart. + */ export const FeedbackStats = ({ data }: ModalPropType): JSX.Element => { + // Colors for the pie chart slices, from green (high ratings) to red (low ratings) const ratingColors = [ '#57bb8a', // Green '#94bd77', @@ -32,6 +42,7 @@ export const FeedbackStats = ({ data }: ModalPropType): JSX.Element => { '#dd776e', // Red ]; + // Count the number of feedbacks for each rating const count: Record = {}; data.event.feedback.forEach((feedback: FeedbackType) => { @@ -39,6 +50,7 @@ export const FeedbackStats = ({ data }: ModalPropType): JSX.Element => { else count[feedback.rating] = 1; }); + // Prepare data for the pie chart const chartData = []; for (let rating = 0; rating <= 5; rating++) { if (rating in count) diff --git a/src/components/EventStats/Statistics/Review.tsx b/src/components/EventStats/Statistics/Review.tsx index 0afc687023..343a8107c3 100644 --- a/src/components/EventStats/Statistics/Review.tsx +++ b/src/components/EventStats/Statistics/Review.tsx @@ -2,6 +2,7 @@ import React from 'react'; import Card from 'react-bootstrap/Card'; import Rating from '@mui/material/Rating'; +// Props for the ReviewStats component type ModalPropType = { data: { event: { @@ -12,13 +13,22 @@ type ModalPropType = { }; }; +// Type representing individual feedback type FeedbackType = { _id: string; rating: number; review: string | null; }; +/** + * Component that displays reviews for an event. + * Shows a list of reviews with ratings and text. + * + * @param data - Data containing event feedback to be displayed. + * @returns JSX element representing the reviews card. + */ export const ReviewStats = ({ data }: ModalPropType): JSX.Element => { + // Filter out feedback that has a review const reviews = data.event.feedback.filter( (feedback: FeedbackType) => feedback.review != null, ); diff --git a/src/components/HolidayCards/HolidayCard.tsx b/src/components/HolidayCards/HolidayCard.tsx index 0235659ee2..56ac86405d 100644 --- a/src/components/HolidayCards/HolidayCard.tsx +++ b/src/components/HolidayCards/HolidayCard.tsx @@ -1,9 +1,17 @@ import React from 'react'; import styles from './HolidayCard.module.css'; +// Props for the HolidayCard component interface InterfaceHolidayList { holidayName: string; } + +/** + * Component that displays a card with the name of a holiday. + * + * @param props - Contains the holidayName to be displayed on the card. + * @returns JSX element representing a card with the holiday name. + */ const HolidayCard = (props: InterfaceHolidayList): JSX.Element => { /*istanbul ignore next*/ return
    {props?.holidayName}
    ; diff --git a/src/components/IconComponent/IconComponent.test.tsx b/src/components/IconComponent/IconComponent.test.tsx index e8faa75404..686a8e6f75 100644 --- a/src/components/IconComponent/IconComponent.test.tsx +++ b/src/components/IconComponent/IconComponent.test.tsx @@ -1,7 +1,12 @@ +import React from 'react'; import { render, screen } from '@testing-library/react'; import IconComponent from './IconComponent'; -import React from 'react'; + const screenTestIdMap: Record> = { + MyOrganizations: { + name: 'My Organizations', + testId: 'Icon-Component-MyOrganizationsIcon', + }, Dashboard: { name: 'Dashboard', testId: 'Icon-Component-DashboardIcon', @@ -10,6 +15,18 @@ const screenTestIdMap: Record> = { name: 'People', testId: 'Icon-Component-PeopleIcon', }, + Tags: { + name: 'Tags', + testId: 'Icon-Component-TagsIcon', + }, + Tag: { + name: 'Tag', + testId: 'Icon-Component-TagIcon', + }, + Requests: { + name: 'Requests', + testId: 'Icon-Component-RequestsIcon', + }, Events: { name: 'Events', testId: 'Icon-Component-EventsIcon', @@ -22,10 +39,6 @@ const screenTestIdMap: Record> = { name: 'Posts', testId: 'Icon-Component-PostsIcon', }, - Funds: { - name: 'Funds', - testId: 'Icon-Component-Funds', - }, BlockUnblock: { name: 'Block/Unblock', testId: 'Block/Icon-Component-UnblockIcon', @@ -38,11 +51,7 @@ const screenTestIdMap: Record> = { name: 'Settings', testId: 'Icon-Component-SettingsIcon', }, - AllOrganizations: { - name: 'My Organizations', - testId: 'Icon-Component-MyOrganizationsIcon', - }, - ListEventRegistrant: { + ListEventRegistrants: { name: 'List Event Registrants', testId: 'Icon-Component-List-Event-Registrants', }, @@ -50,18 +59,30 @@ const screenTestIdMap: Record> = { name: 'Check In Registrants', testId: 'Icon-Component-Check-In-Registrants', }, - EventStats: { - name: 'Event Stats', - testId: 'Icon-Component-Event-Stats', - }, Advertisement: { name: 'Advertisement', testId: 'Icon-Component-Advertisement', }, + Funds: { + name: 'Funds', + testId: 'Icon-Component-Funds', + }, Venues: { name: 'Venues', testId: 'Icon-Component-Venues', }, + Donate: { + name: 'Donate', + testId: 'Icon-Component-Donate', + }, + Campaigns: { + name: 'Campaigns', + testId: 'Icon-Component-Campaigns', + }, + MyPledges: { + name: 'My Pledges', + testId: 'Icon-Component-My-Pledges', + }, default: { name: 'default', testId: 'Icon-Component-DefaultIcon', diff --git a/src/components/IconComponent/IconComponent.tsx b/src/components/IconComponent/IconComponent.tsx index 17f9af8b32..4708dc7966 100644 --- a/src/components/IconComponent/IconComponent.tsx +++ b/src/components/IconComponent/IconComponent.tsx @@ -1,22 +1,24 @@ -import { QuestionMarkOutlined } from '@mui/icons-material'; -import { ReactComponent as ActionItemIcon } from 'assets/svgs/actionItem.svg'; -import { ReactComponent as AgendaCategoryIcon } from 'assets/svgs/agenda-category-icon.svg'; -import { ReactComponent as BlockUserIcon } from 'assets/svgs/blockUser.svg'; -import { ReactComponent as CheckInRegistrantsIcon } from 'assets/svgs/checkInRegistrants.svg'; -import { ReactComponent as DashboardIcon } from 'assets/svgs/dashboard.svg'; -import { ReactComponent as EventStatsIcon } from 'assets/svgs/eventStats.svg'; -import { ReactComponent as EventsIcon } from 'assets/svgs/events.svg'; -import { ReactComponent as FundsIcon } from 'assets/svgs/funds.svg'; -import { ReactComponent as ListEventRegistrantsIcon } from 'assets/svgs/listEventRegistrants.svg'; -import { ReactComponent as OrganizationsIcon } from 'assets/svgs/organizations.svg'; -import { ReactComponent as PeopleIcon } from 'assets/svgs/people.svg'; -import { ReactComponent as PluginsIcon } from 'assets/svgs/plugins.svg'; -import { ReactComponent as PostsIcon } from 'assets/svgs/posts.svg'; -import { ReactComponent as SettingsIcon } from 'assets/svgs/settings.svg'; -import { ReactComponent as VenueIcon } from 'assets/svgs/venues.svg'; -import { ReactComponent as RequestsIcon } from 'assets/svgs/requests.svg'; -// import { ReactComponent as HomeIcon } from 'assets/svgs/home.svg'; -// import { ReactComponent as DonateIcon } from 'assets/svgs/donate.svg'; +import { + QuestionMarkOutlined, + ContactPageOutlined, + NewspaperOutlined, +} from '@mui/icons-material'; +import ActionItemIcon from 'assets/svgs/actionItem.svg?react'; +import BlockUserIcon from 'assets/svgs/blockUser.svg?react'; +import CheckInRegistrantsIcon from 'assets/svgs/checkInRegistrants.svg?react'; +import DashboardIcon from 'assets/svgs/dashboard.svg?react'; +import EventsIcon from 'assets/svgs/events.svg?react'; +import FundsIcon from 'assets/svgs/funds.svg?react'; +import ListEventRegistrantsIcon from 'assets/svgs/listEventRegistrants.svg?react'; +import OrganizationsIcon from 'assets/svgs/organizations.svg?react'; +import PeopleIcon from 'assets/svgs/people.svg?react'; +import TagsIcon from 'assets/svgs/tags.svg?react'; +import TagIcon from 'assets/svgs/tag.svg?react'; +import PluginsIcon from 'assets/svgs/plugins.svg?react'; +import PostsIcon from 'assets/svgs/posts.svg?react'; +import SettingsIcon from 'assets/svgs/settings.svg?react'; +import VenueIcon from 'assets/svgs/venues.svg?react'; +import RequestsIcon from 'assets/svgs/requests.svg?react'; import React from 'react'; @@ -26,7 +28,12 @@ export interface InterfaceIconComponent { height?: string; width?: string; } - +/** + * Renders an icon based on the provided name. + * + * @param props - Contains the name of the icon and optional styles (fill, height, width). + * @returns JSX element representing the icon. + */ const iconComponent = (props: InterfaceIconComponent): JSX.Element => { switch (props.name) { case 'My Organizations': @@ -42,6 +49,10 @@ const iconComponent = (props: InterfaceIconComponent): JSX.Element => { ); case 'People': return ; + case 'Tags': + return ; + case 'Tag': + return ; case 'Requests': return ( @@ -55,13 +66,6 @@ const iconComponent = (props: InterfaceIconComponent): JSX.Element => { data-testid="Icon-Component-ActionItemIcon" /> ); - case 'Agenda Items Category': - return ( - - ); case 'Posts': return ; case 'Block/Unblock': @@ -99,13 +103,6 @@ const iconComponent = (props: InterfaceIconComponent): JSX.Element => { stroke={props.fill} /> ); - case 'Event Stats': - return ( - - ); case 'Advertisement': return ( { return ( ); - case 'Home': - return ( - - ); case 'Donate': return ( ); + case 'Campaigns': + return ( + + ); + case 'My Pledges': + return ( + + ); default: return ( ); diff --git a/src/components/LeftDrawer/LeftDrawer.test.tsx b/src/components/LeftDrawer/LeftDrawer.test.tsx index 3873d66dc2..6701d2d4bb 100644 --- a/src/components/LeftDrawer/LeftDrawer.test.tsx +++ b/src/components/LeftDrawer/LeftDrawer.test.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { act } from 'react'; import { fireEvent, render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import 'jest-localstorage-mock'; @@ -63,102 +63,131 @@ afterEach(() => { }); describe('Testing Left Drawer component for SUPERADMIN', () => { - test('Component should be rendered properly', () => { - setItem('UserImage', ''); - setItem('UserImage', ''); - setItem('SuperAdmin', true); - setItem('FirstName', 'John'); - setItem('LastName', 'Doe'); + test('Component should be rendered properly', async () => { setItem('UserImage', ''); setItem('SuperAdmin', true); setItem('FirstName', 'John'); setItem('LastName', 'Doe'); - render( - - - - - - - , - ); + + await act(async () => { + render( + + + + + + + , + ); + }); expect(screen.getByText('My Organizations')).toBeInTheDocument(); expect(screen.getByText('Users')).toBeInTheDocument(); expect(screen.getByText('Community Profile')).toBeInTheDocument(); - expect(screen.getByText('Community Profile')).toBeInTheDocument(); expect(screen.getByText('Talawa Admin Portal')).toBeInTheDocument(); const orgsBtn = screen.getByTestId(/orgsBtn/i); const rolesBtn = screen.getByTestId(/rolesBtn/i); const communityProfileBtn = screen.getByTestId(/communityProfileBtn/i); - orgsBtn.click(); + await act(async () => { + orgsBtn.click(); + }); + expect( orgsBtn.className.includes('text-white btn btn-success'), ).toBeTruthy(); expect(rolesBtn.className.includes('text-secondary btn')).toBeTruthy(); - expect(rolesBtn.className.includes('text-secondary btn')).toBeTruthy(); expect( communityProfileBtn.className.includes('text-secondary btn'), ).toBeTruthy(); - // Send to roles screen - userEvent.click(rolesBtn); + await act(async () => { + userEvent.click(rolesBtn); + }); + expect(global.window.location.pathname).toContain('/users'); - userEvent.click(communityProfileBtn); + + await act(async () => { + userEvent.click(communityProfileBtn); + }); }); - test('Testing Drawer when hideDrawer is null', () => { + test('Testing Drawer when hideDrawer is null', async () => { const tempProps: InterfaceLeftDrawerProps = { ...props, hideDrawer: false, }; - render( - - - - - - - , - ); + await act(async () => { + render( + + + + + + + , + ); + }); }); - test('Testing Drawer when hideDrawer is false', () => { + + test('Testing Drawer when hideDrawer is false', async () => { const tempProps: InterfaceLeftDrawerProps = { ...props, hideDrawer: false, }; + + await act(async () => { + render( + + + + + + + , + ); + }); }); - test('Testing Drawer when the screen size is less than or equal to 820px', () => { + + test('Testing Drawer when the screen size is less than or equal to 820px', async () => { const tempProps: InterfaceLeftDrawerProps = { ...props, hideDrawer: false, }; resizeWindow(800); - render( - - - - - - - , - ); + + await act(async () => { + render( + + + + + + + , + ); + }); + expect(screen.getByText('My Organizations')).toBeInTheDocument(); expect(screen.getByText('Talawa Admin Portal')).toBeInTheDocument(); const orgsBtn = screen.getByTestId(/orgsBtn/i); - orgsBtn.click(); + await act(async () => { + orgsBtn.click(); + }); + expect( orgsBtn.className.includes('text-white btn btn-success'), ).toBeTruthy(); }); +}); - describe('Testing Left Drawer component for ADMIN', () => { - test('Components should be rendered properly', () => { +describe('Testing Left Drawer component for ADMIN', () => { + test('Components should be rendered properly', async () => { + await act(async () => { render( @@ -168,24 +197,30 @@ describe('Testing Left Drawer component for SUPERADMIN', () => { , ); + }); + + expect(screen.getByText('My Organizations')).toBeInTheDocument(); + expect(screen.getByText('Talawa Admin Portal')).toBeInTheDocument(); - expect(screen.getByText('My Organizations')).toBeInTheDocument(); - expect(screen.getByText('Talawa Admin Portal')).toBeInTheDocument(); + expect(screen.getAllByText(/admin/i)).toHaveLength(1); - expect(screen.getAllByText(/admin/i)).toHaveLength(1); - expect(screen.getAllByText(/admin/i)).toHaveLength(1); + const orgsBtn = screen.getByTestId(/orgsBtn/i); - const orgsBtn = screen.getByTestId(/orgsBtn/i); + await act(async () => { orgsBtn.click(); - expect( - orgsBtn.className.includes('text-white btn btn-success'), - ).toBeTruthy(); + }); - // These screens arent meant for admins so they should not be present - expect(screen.queryByTestId(/rolesBtn/i)).toBeNull(); + expect( + orgsBtn.className.includes('text-white btn btn-success'), + ).toBeTruthy(); + // These screens aren't meant for admins, so they should not be present + expect(screen.queryByTestId(/rolesBtn/i)).toBeNull(); + + await act(async () => { userEvent.click(orgsBtn); - expect(global.window.location.pathname).toContain('/orglist'); }); + + expect(global.window.location.pathname).toContain('/orglist'); }); }); diff --git a/src/components/LeftDrawer/LeftDrawer.tsx b/src/components/LeftDrawer/LeftDrawer.tsx index dc501d6185..4628603ba1 100644 --- a/src/components/LeftDrawer/LeftDrawer.tsx +++ b/src/components/LeftDrawer/LeftDrawer.tsx @@ -2,18 +2,25 @@ import React from 'react'; import Button from 'react-bootstrap/Button'; import { useTranslation } from 'react-i18next'; import { NavLink } from 'react-router-dom'; -import { ReactComponent as OrganizationsIcon } from 'assets/svgs/organizations.svg'; -import { ReactComponent as RolesIcon } from 'assets/svgs/roles.svg'; -import { ReactComponent as SettingsIcon } from 'assets/svgs/settings.svg'; -import { ReactComponent as TalawaLogo } from 'assets/svgs/talawa.svg'; +import OrganizationsIcon from 'assets/svgs/organizations.svg?react'; +import RolesIcon from 'assets/svgs/roles.svg?react'; +import SettingsIcon from 'assets/svgs/settings.svg?react'; +import TalawaLogo from 'assets/svgs/talawa.svg?react'; import styles from './LeftDrawer.module.css'; import useLocalStorage from 'utils/useLocalstorage'; export interface InterfaceLeftDrawerProps { - hideDrawer: boolean | null; - setHideDrawer: React.Dispatch>; + hideDrawer: boolean | null; // Controls the visibility of the drawer + setHideDrawer: React.Dispatch>; // Function to set the visibility state } +/** + * LeftDrawer component for displaying navigation options. + * + * @param hideDrawer - Determines if the drawer should be hidden or shown. + * @param setHideDrawer - Function to update the visibility state of the drawer. + * @returns JSX element for the left navigation drawer. + */ const leftDrawer = ({ hideDrawer, setHideDrawer, @@ -24,6 +31,9 @@ const leftDrawer = ({ const { getItem } = useLocalStorage(); const superAdmin = getItem('SuperAdmin'); + /** + * Handles link click to hide the drawer on smaller screens. + */ const handleLinkClick = (): void => { if (window.innerWidth <= 820) { setHideDrawer(true); diff --git a/src/components/LeftDrawerOrg/LeftDrawerOrg.module.css b/src/components/LeftDrawerOrg/LeftDrawerOrg.module.css index 54560e7969..e792ef34bb 100644 --- a/src/components/LeftDrawerOrg/LeftDrawerOrg.module.css +++ b/src/components/LeftDrawerOrg/LeftDrawerOrg.module.css @@ -7,12 +7,21 @@ z-index: 100; display: flex; flex-direction: column; - padding: 0.8rem 1rem 0 1rem; + padding: 0.8rem 0rem 0 1rem; background-color: var(--bs-white); transition: 0.5s; font-family: var(--bs-leftDrawer-font-family); } +.avatarContainer { + display: flex; + justify-content: center; + align-items: center; + margin: 1rem 0; + width: 75%; + height: 75%; +} + .activeDrawer { width: calc(300px + 2rem); position: fixed; @@ -61,6 +70,8 @@ .leftDrawer .optionList { height: 100%; + overflow-y: scroll; + padding-bottom: 1.5rem; } .leftDrawer .optionList button { @@ -114,6 +125,7 @@ .leftDrawer .imageContainer { width: 68px; + margin-left: 0.75rem; margin-right: 8px; } @@ -151,7 +163,7 @@ @media (max-width: 1120px) { .leftDrawer { width: calc(250px + 2rem); - padding: 1rem 1rem 0 1rem; + padding: 1rem 0rem 0 1rem; } } @@ -186,7 +198,7 @@ } @media (max-height: 650px) { .leftDrawer { - padding: 0.5rem 0.8rem 0 0.8rem; + padding: 0.5rem 0rem 0 0.8rem; width: calc(250px); } .leftDrawer .talawaText { @@ -213,7 +225,7 @@ } .leftDrawer .imageContainer { width: 40px; - margin-left: 5px; + margin-left: 0.75rem; margin-right: 12px; } .leftDrawer .imageContainer img { diff --git a/src/components/LeftDrawerOrg/LeftDrawerOrg.test.tsx b/src/components/LeftDrawerOrg/LeftDrawerOrg.test.tsx index 9bd2ffd1d9..2a0ef3815d 100644 --- a/src/components/LeftDrawerOrg/LeftDrawerOrg.test.tsx +++ b/src/components/LeftDrawerOrg/LeftDrawerOrg.test.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { act } from 'react'; import { fireEvent, render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import 'jest-localstorage-mock'; @@ -12,7 +12,6 @@ import { Provider } from 'react-redux'; import { MockedProvider } from '@apollo/react-testing'; import { store } from 'state/store'; import { ORGANIZATIONS_LIST } from 'GraphQl/Queries/Queries'; -import { act } from 'react-dom/test-utils'; import { StaticMockLink } from 'utils/StaticMockLink'; import { REVOKE_REFRESH_TOKEN } from 'GraphQl/Mutations/mutations'; import useLocalStorage from 'utils/useLocalstorage'; @@ -24,41 +23,41 @@ const props: InterfaceLeftDrawerProps = { targets: [ { name: 'Dashboard', - url: '/orgdash/id=123', + url: '/orgdash/123', }, { name: 'People', - url: '/orgpeople/id=123', + url: '/orgpeople/123', }, { name: 'Events', - url: '/orgevents/id=123', + url: '/orgevents/123', }, { name: 'Posts', - url: '/orgpost/id=123', + url: '/orgpost/123', }, { name: 'Block/Unblock', - url: '/blockuser/id=123', + url: '/blockuser/123', }, { name: 'Plugins', subTargets: [ { name: 'Plugin Store', - url: '/orgstore/id=123', + url: '/orgstore/123', icon: 'fa-store', }, ], }, { name: 'Settings', - url: '/orgsetting/id=123', + url: '/orgsetting/123', }, { name: 'All Organizations', - url: '/orglist/id=123', + url: '/orglist/123', }, ], hideDrawer: false, @@ -327,7 +326,7 @@ describe('Testing LeftDrawerOrg component for SUPERADMIN', () => { ); await wait(); userEvent.click(screen.getByText('Dashboard')); - expect(global.window.location.pathname).toContain('/orgdash/id=123'); + expect(global.window.location.pathname).toContain('/orgdash/123'); }); test('Testing when screen size is less than 820px', async () => { @@ -345,13 +344,13 @@ describe('Testing LeftDrawerOrg component for SUPERADMIN', () => { ); await wait(); resizeWindow(800); - expect(screen.getByText(/Dashboard/i)).toBeInTheDocument(); - expect(screen.getByText(/People/i)).toBeInTheDocument(); + expect(screen.getAllByText(/Dashboard/i)[0]).toBeInTheDocument(); + expect(screen.getAllByText(/People/i)[0]).toBeInTheDocument(); const peopelBtn = screen.getByTestId(/People/i); userEvent.click(peopelBtn); await wait(); - expect(window.location.pathname).toContain('/orgpeople/id=123'); + expect(window.location.pathname).toContain('/orgpeople/123'); }); test('Testing when image is present for Organization', async () => { @@ -391,7 +390,7 @@ describe('Testing LeftDrawerOrg component for SUPERADMIN', () => { ); await wait(); expect( - screen.getByText(/Error Occured while loading the Organization/i), + screen.getByText(/Error occured while loading Organization data/i), ).toBeInTheDocument(); }); diff --git a/src/components/LeftDrawerOrg/LeftDrawerOrg.tsx b/src/components/LeftDrawerOrg/LeftDrawerOrg.tsx index 6cc501db45..3a3ba378cf 100644 --- a/src/components/LeftDrawerOrg/LeftDrawerOrg.tsx +++ b/src/components/LeftDrawerOrg/LeftDrawerOrg.tsx @@ -9,8 +9,8 @@ import { useTranslation } from 'react-i18next'; import { NavLink } from 'react-router-dom'; import type { TargetsType } from 'state/reducers/routesReducer'; import type { InterfaceQueryOrganizationsListObject } from 'utils/interfaces'; -import { ReactComponent as AngleRightIcon } from 'assets/svgs/angleRight.svg'; -import { ReactComponent as TalawaLogo } from 'assets/svgs/talawa.svg'; +import AngleRightIcon from 'assets/svgs/angleRight.svg?react'; +import TalawaLogo from 'assets/svgs/talawa.svg?react'; import styles from './LeftDrawerOrg.module.css'; import Avatar from 'components/Avatar/Avatar'; @@ -21,6 +21,15 @@ export interface InterfaceLeftDrawerProps { setHideDrawer: React.Dispatch>; } +/** + * LeftDrawerOrg component for displaying organization details and navigation options. + * + * @param orgId - ID of the current organization. + * @param targets - List of navigation targets. + * @param hideDrawer - Determines if the drawer should be hidden or shown. + * @param setHideDrawer - Function to update the visibility state of the drawer. + * @returns JSX element for the left navigation drawer with organization details. + */ const leftDrawerOrg = ({ targets, orgId, @@ -28,7 +37,8 @@ const leftDrawerOrg = ({ setHideDrawer, }: InterfaceLeftDrawerProps): JSX.Element => { const { t: tCommon } = useTranslation('common'); - const [showDropdown, setShowDropdown] = React.useState(false); + const { t: tErrors } = useTranslation('errors'); + const [showDropdown, setShowDropdown] = useState(false); const [organization, setOrganization] = useState(); @@ -43,18 +53,21 @@ const leftDrawerOrg = ({ } = useQuery(ORGANIZATIONS_LIST, { variables: { id: orgId }, }); - // Set organization data + + // Set organization data when query data is available useEffect(() => { let isMounted = true; if (data && isMounted) { setOrganization(data?.organizations[0]); - console.log(targets, 'targets'); } return () => { isMounted = false; }; }, [data]); + /** + * Handles link click to hide the drawer on smaller screens. + */ const handleLinkClick = (): void => { if (window.innerWidth <= 820) { setHideDrawer(true); @@ -82,7 +95,7 @@ const leftDrawerOrg = ({
    {/* Organization Section */} -
    +
    {loading ? ( <>
    - Error Occured while loading the Organization + {tErrors('errorLoading', { entity: 'Organization' })} ) : ( @@ -110,6 +123,7 @@ const leftDrawerOrg = ({ ) : ( )} @@ -126,10 +140,10 @@ const leftDrawerOrg = ({
    {/* Options List */} +
    + {tCommon('menu')} +
    -
    - {tCommon('menu')} -
    {targets.map(({ name, url }, index) => { return url ? ( diff --git a/src/components/Loader/Loader.tsx b/src/components/Loader/Loader.tsx index fe5ddef793..b59c735175 100644 --- a/src/components/Loader/Loader.tsx +++ b/src/components/Loader/Loader.tsx @@ -3,10 +3,17 @@ import styles from './Loader.module.css'; import { Spinner } from 'react-bootstrap'; interface InterfaceLoaderProps { - styles?: StyleSheet | string; - size?: 'sm' | 'lg' | 'xl'; + styles?: StyleSheet | string; // Custom styles for the spinner wrapper + size?: 'sm' | 'lg' | 'xl'; // Size of the spinner } +/** + * Loader component for displaying a loading spinner. + * + * @param styles - Optional custom styles for the spinner wrapper. + * @param size - Size of the spinner. Can be 'sm', 'lg', or 'xl'. + * @returns JSX element for a loading spinner. + */ const Loader = (props: InterfaceLoaderProps): JSX.Element => { return ( <> diff --git a/src/components/LoginPortalToggle/LoginPortalToggle.test.tsx b/src/components/LoginPortalToggle/LoginPortalToggle.test.tsx index ac971e52ea..327e6cccea 100644 --- a/src/components/LoginPortalToggle/LoginPortalToggle.test.tsx +++ b/src/components/LoginPortalToggle/LoginPortalToggle.test.tsx @@ -1,5 +1,5 @@ -import React from 'react'; -import { act, render } from '@testing-library/react'; +import React, { act } from 'react'; +import { render } from '@testing-library/react'; import { Provider } from 'react-redux'; import { BrowserRouter } from 'react-router-dom'; import { I18nextProvider } from 'react-i18next'; diff --git a/src/components/LoginPortalToggle/LoginPortalToggle.tsx b/src/components/LoginPortalToggle/LoginPortalToggle.tsx index c1feb9f4da..76305b02d3 100644 --- a/src/components/LoginPortalToggle/LoginPortalToggle.tsx +++ b/src/components/LoginPortalToggle/LoginPortalToggle.tsx @@ -6,25 +6,36 @@ import Row from 'react-bootstrap/Row'; import { NavLink } from 'react-router-dom'; interface InterfaceLoginPortalToggleProps { - onToggle: (role: 'admin' | 'user') => void; + onToggle: (role: 'admin' | 'user') => void; // Callback function for role change } +/** + * Component for toggling between admin and user login portals. + * + * @param onToggle - Callback function to handle role changes ('admin' or 'user'). + * @returns JSX element for login portal toggle. + */ function loginPortalToggle({ onToggle, }: InterfaceLoginPortalToggleProps): JSX.Element { const { t: tCommon } = useTranslation('common'); - const [activeRole, setActiveRole] = useState<'admin' | 'user'>('admin'); + const [activeRole, setActiveRole] = useState<'admin' | 'user'>('admin'); // Default role is 'admin' + /** + * Handles navigation link click and updates the active role. + * + * @param role - The role to be activated ('admin' or 'user'). + */ const handleNavLinkClick = (role: 'admin' | 'user'): void => { - onToggle(role); - setActiveRole(role); + onToggle(role); // Invoke the callback with the new role + setActiveRole(role); // Update the active role }; return ( handleNavLinkClick('admin')} > @@ -33,7 +44,7 @@ function loginPortalToggle({ handleNavLinkClick('user')} > diff --git a/src/components/MemberRequestCard/MemberRequestCard.test.tsx b/src/components/MemberRequestCard/MemberRequestCard.test.tsx index 121213e4e7..a38a046ea2 100644 --- a/src/components/MemberRequestCard/MemberRequestCard.test.tsx +++ b/src/components/MemberRequestCard/MemberRequestCard.test.tsx @@ -1,5 +1,5 @@ -import React from 'react'; -import { act, render, screen } from '@testing-library/react'; +import React, { act } from 'react'; +import { render, screen } from '@testing-library/react'; import { MockedProvider } from '@apollo/react-testing'; import userEvent from '@testing-library/user-event'; import { I18nextProvider } from 'react-i18next'; @@ -16,7 +16,7 @@ const MOCKS = [ { request: { query: ACCEPT_ORGANIZATION_REQUEST_MUTATION, - variable: { id: '123' }, + variables: { id: '123' }, }, result: { data: { @@ -31,7 +31,7 @@ const MOCKS = [ { request: { query: REJECT_ORGANIZATION_REQUEST_MUTATION, - variable: { id: '234' }, + variables: { userid: '234' }, }, result: { data: { @@ -44,7 +44,9 @@ const MOCKS = [ }, }, ]; + const link = new StaticMockLink(MOCKS, true); + async function wait(ms = 100): Promise { await act(() => { return new Promise((resolve) => { @@ -55,7 +57,6 @@ async function wait(ms = 100): Promise { describe('Testing Member Request Card', () => { const props = { - key: '123', id: '1', memberName: 'John Doe', memberLocation: 'India', @@ -89,14 +90,13 @@ describe('Testing Member Request Card', () => { expect(screen.getByText(props.email)).toBeInTheDocument(); }); - it('Should render text elements when props value is not passed', async () => { + it('should render text elements when props value is not passed', async () => { global.confirm = (): boolean => false; render( => { try { await acceptMutation({ @@ -43,7 +52,7 @@ function memberRequestCard( }); /* istanbul ignore next */ - toast.success(t('memberAdded')); + toast.success(t('memberAdded') as string); /* istanbul ignore next */ setTimeout(() => { window.location.reload(); @@ -54,6 +63,10 @@ function memberRequestCard( } }; + /** + * Handles rejecting a member request. + * Confirms rejection and reloads the page if confirmed. + */ const rejectMember = async (): Promise => { const sure = window.confirm('Are you sure you want to Reject Request ?'); if (sure) { @@ -118,9 +131,8 @@ function memberRequestCard(
    -
    +
    ); } -export {}; -export default memberRequestCard; +export default MemberRequestCard; diff --git a/src/components/NotFound/NotFound.tsx b/src/components/NotFound/NotFound.tsx index 6e2853cf82..6b5332bbcf 100644 --- a/src/components/NotFound/NotFound.tsx +++ b/src/components/NotFound/NotFound.tsx @@ -4,10 +4,17 @@ import { useTranslation } from 'react-i18next'; import styles from './NotFound.module.css'; interface InterfaceNotFoundProps { - title: string; - keyPrefix: string; + title: string; // Title of the page or resource not found + keyPrefix: string; // Translation key prefix } +/** + * Component to display a "Not Found" message. + * + * @param title - Title of the page or resource that was not found. + * @param keyPrefix - Prefix for translation keys. + * @returns JSX element for the "Not Found" page. + */ function notFound(props: InterfaceNotFoundProps): JSX.Element { const key = props.keyPrefix.toString(); const { t } = useTranslation('translation', { diff --git a/src/components/OrgActionItemCategories/OrgActionItemCategories.module.css b/src/components/OrgActionItemCategories/OrgActionItemCategories.module.css deleted file mode 100644 index ac9f4a5900..0000000000 --- a/src/components/OrgActionItemCategories/OrgActionItemCategories.module.css +++ /dev/null @@ -1,33 +0,0 @@ -.addButton { - width: 7em; - position: absolute; - right: 1rem; - top: 1rem; -} - -.createModal { - margin-top: 20vh; - margin-left: 13vw; - max-width: 80vw; -} - -.icon { - transform: scale(1.5); - color: var(--bs-danger); - margin-bottom: 1rem; -} - -.message { - display: flex; - justify-content: center; - align-items: center; - flex-direction: column; -} - -.titlemodal { - color: var(--bs-gray-600); - font-weight: 600; - font-size: 20px; - margin-top: 1rem; - width: 65%; -} diff --git a/src/components/OrgActionItemCategories/OrgActionItemCategories.test.tsx b/src/components/OrgActionItemCategories/OrgActionItemCategories.test.tsx deleted file mode 100644 index d410611c61..0000000000 --- a/src/components/OrgActionItemCategories/OrgActionItemCategories.test.tsx +++ /dev/null @@ -1,372 +0,0 @@ -import React from 'react'; -import { - render, - screen, - fireEvent, - waitFor, - act, -} from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import 'jest-localstorage-mock'; -import { MockedProvider } from '@apollo/client/testing'; -import 'jest-location-mock'; -import { I18nextProvider } from 'react-i18next'; -import { Provider } from 'react-redux'; -import { BrowserRouter } from 'react-router-dom'; -import i18n from 'utils/i18nForTest'; -import { toast } from 'react-toastify'; - -import { store } from 'state/store'; -import { StaticMockLink } from 'utils/StaticMockLink'; - -import OrgActionItemCategories from './OrgActionItemCategories'; -import { - MOCKS, - MOCKS_ERROR_QUERY, - MOCKS_ERROR_MUTATIONS, -} from './OrgActionItemCategoryMocks'; - -jest.mock('react-toastify', () => ({ - toast: { - success: jest.fn(), - error: jest.fn(), - }, -})); -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useParams: () => ({ orgId: '123' }), -})); - -async function wait(ms = 100): Promise { - await act(() => { - return new Promise((resolve) => { - setTimeout(resolve, ms); - }); - }); -} - -const link = new StaticMockLink(MOCKS, true); -const link2 = new StaticMockLink(MOCKS_ERROR_QUERY, true); -const link3 = new StaticMockLink(MOCKS_ERROR_MUTATIONS, true); - -const translations = { - ...JSON.parse( - JSON.stringify( - i18n.getDataByLanguage('en')?.translation.orgActionItemCategories ?? {}, - ), - ), - ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.common ?? {})), - ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.errors ?? {})), -}; - -describe('Testing Action Item Categories Component', () => { - test('Component loads correctly', async () => { - window.location.assign('/orgsetting/id=123'); - const { getByText } = render( - - - - - {} - - - - , - ); - - await wait(); - - await waitFor(() => { - expect(getByText(translations.create)).toBeInTheDocument(); - }); - }); - - test('render error component on unsuccessful query', async () => { - window.location.assign('/orgsetting/id=123'); - const { queryByText } = render( - - - - - {} - - - - , - ); - - await wait(); - - await waitFor(() => { - expect(queryByText(translations.create)).not.toBeInTheDocument(); - }); - }); - - test('opens and closes create and update modals on button clicks', async () => { - window.location.assign('/orgsetting/id=123'); - render( - - - - - {} - - - - , - ); - - await wait(); - - await waitFor(() => { - userEvent.click(screen.getByTestId('actionItemCategoryModalOpenBtn')); - userEvent.click(screen.getByTestId('actionItemCategoryModalCloseBtn')); - }); - - await waitFor(() => { - userEvent.click( - screen.getAllByTestId('actionItemCategoryUpdateModalOpenBtn')[0], - ); - userEvent.click(screen.getByTestId('actionItemCategoryModalCloseBtn')); - }); - }); - - test('create a new action item category', async () => { - window.location.assign('/orgsetting/id=123'); - render( - - - - - {} - - - - , - ); - - await wait(); - - await waitFor(() => { - userEvent.click(screen.getByTestId('actionItemCategoryModalOpenBtn')); - userEvent.type( - screen.getByPlaceholderText(translations.enterName), - 'ActionItemCategory 4', - ); - - userEvent.click(screen.getByTestId('formSubmitButton')); - }); - - await waitFor(() => { - expect(toast.success).toBeCalledWith(translations.successfulCreation); - }); - }); - - test('toast error on unsuccessful creation', async () => { - window.location.assign('/orgsetting/id=123'); - render( - - - - - {} - - - - , - ); - - await wait(); - - await waitFor(() => { - userEvent.click(screen.getByTestId('actionItemCategoryModalOpenBtn')); - userEvent.type( - screen.getByPlaceholderText(translations.enterName), - 'ActionItemCategory 4', - ); - - userEvent.click(screen.getByTestId('formSubmitButton')); - }); - - await waitFor(() => { - expect(toast.error).toHaveBeenCalled(); - }); - }); - - test('update an action item category', async () => { - window.location.assign('/orgsetting/id=123'); - render( - - - - - {} - - - - , - ); - - await wait(); - - await waitFor(() => { - userEvent.click( - screen.getAllByTestId('actionItemCategoryUpdateModalOpenBtn')[0], - ); - - const name = screen.getByPlaceholderText(translations.enterName); - fireEvent.change(name, { target: { value: '' } }); - - userEvent.type( - screen.getByPlaceholderText(translations.enterName), - 'ActionItemCategory 1 updated', - ); - - userEvent.click(screen.getByTestId('formSubmitButton')); - }); - - await waitFor(() => { - expect(toast.success).toBeCalledWith(translations.successfulUpdation); - }); - }); - - test('toast error on unsuccessful updation', async () => { - window.location.assign('/orgsetting/id=123'); - render( - - - - - {} - - - - , - ); - - await wait(); - - await waitFor(() => { - userEvent.click( - screen.getAllByTestId('actionItemCategoryUpdateModalOpenBtn')[0], - ); - - const name = screen.getByPlaceholderText(translations.enterName); - fireEvent.change(name, { target: { value: '' } }); - - userEvent.type( - screen.getByPlaceholderText(translations.enterName), - 'ActionItemCategory 1 updated', - ); - - userEvent.click(screen.getByTestId('formSubmitButton')); - }); - - await waitFor(() => { - expect(toast.error).toHaveBeenCalled(); - }); - }); - - test('toast error on providing the same name on updation', async () => { - window.location.assign('/orgsetting/id=123'); - render( - - - - - {} - - - - , - ); - - await wait(); - - await waitFor(() => { - userEvent.click( - screen.getAllByTestId('actionItemCategoryUpdateModalOpenBtn')[0], - ); - - const name = screen.getByPlaceholderText(translations.enterName); - fireEvent.change(name, { target: { value: '' } }); - - userEvent.type( - screen.getByPlaceholderText(translations.enterName), - 'ActionItemCategory 1', - ); - - userEvent.click(screen.getByTestId('formSubmitButton')); - }); - - await waitFor(() => { - expect(toast.error).toBeCalledWith(translations.sameNameConflict); - }); - }); - - test('toggle the disablity status of an action item category', async () => { - window.location.assign('/orgsetting/id=123'); - render( - - - - - {} - - - - , - ); - - await wait(); - - await waitFor(() => { - userEvent.click(screen.getAllByTestId('disabilityStatusButton')[0]); - }); - - await waitFor(() => { - expect(toast.success).toBeCalledWith(translations.categoryDisabled); - }); - - await waitFor(() => { - userEvent.click(screen.getAllByTestId('disabilityStatusButton')[1]); - }); - - await waitFor(() => { - expect(toast.success).toBeCalledWith(translations.categoryEnabled); - }); - }); - - test('toast error on unsuccessful toggling of the disablity status', async () => { - window.location.assign('/orgsetting/id=123'); - render( - - - - - {} - - - - , - ); - - await wait(); - - await waitFor(() => { - userEvent.click(screen.getAllByTestId('disabilityStatusButton')[0]); - }); - - await waitFor(() => { - expect(toast.error).toHaveBeenCalled(); - }); - - await waitFor(() => { - userEvent.click(screen.getAllByTestId('disabilityStatusButton')[1]); - }); - - await waitFor(() => { - expect(toast.error).toHaveBeenCalled(); - }); - }); -}); diff --git a/src/components/OrgActionItemCategories/OrgActionItemCategories.tsx b/src/components/OrgActionItemCategories/OrgActionItemCategories.tsx deleted file mode 100644 index f893319e38..0000000000 --- a/src/components/OrgActionItemCategories/OrgActionItemCategories.tsx +++ /dev/null @@ -1,292 +0,0 @@ -import type { ChangeEvent } from 'react'; -import React, { useState } from 'react'; -import { Button, Form, Modal } from 'react-bootstrap'; -import styles from './OrgActionItemCategories.module.css'; -import { useTranslation } from 'react-i18next'; -import { toast } from 'react-toastify'; -import { WarningAmberRounded } from '@mui/icons-material'; - -import { useMutation, useQuery } from '@apollo/client'; -import { - CREATE_ACTION_ITEM_CATEGORY_MUTATION, - UPDATE_ACTION_ITEM_CATEGORY_MUTATION, -} from 'GraphQl/Mutations/mutations'; -import { ACTION_ITEM_CATEGORY_LIST } from 'GraphQl/Queries/Queries'; -import type { InterfaceActionItemCategoryList } from 'utils/interfaces'; -import Loader from 'components/Loader/Loader'; -import { useParams } from 'react-router-dom'; - -type ModalType = 'Create' | 'Update'; - -const OrgActionItemCategories = (): JSX.Element => { - const { t } = useTranslation('translation', { - keyPrefix: 'orgActionItemCategories', - }); - const { t: tCommon } = useTranslation('common'); - - const [modalIsOpen, setModalIsOpen] = useState(false); - const [modalType, setModalType] = useState('Create'); - const [categoryId, setCategoryId] = useState(''); - - const [name, setName] = useState(''); - const [currName, setCurrName] = useState(''); - - const { orgId: currentUrl } = useParams(); - - const { - data, - loading, - error, - refetch, - }: { - data: InterfaceActionItemCategoryList | undefined; - loading: boolean; - error?: Error | undefined; - refetch: () => void; - } = useQuery(ACTION_ITEM_CATEGORY_LIST, { - variables: { - organizationId: currentUrl, - }, - notifyOnNetworkStatusChange: true, - }); - - const [createActionItemCategory] = useMutation( - CREATE_ACTION_ITEM_CATEGORY_MUTATION, - ); - - const [updateActionItemCategory] = useMutation( - UPDATE_ACTION_ITEM_CATEGORY_MUTATION, - ); - - const handleCreate = async ( - e: ChangeEvent, - ): Promise => { - e.preventDefault(); - try { - await createActionItemCategory({ - variables: { - name, - organizationId: currentUrl, - }, - }); - - setName(''); - refetch(); - - setModalIsOpen(false); - - toast.success(t('successfulCreation')); - } catch (error: unknown) { - if (error instanceof Error) { - toast.error(error.message); - console.log(error.message); - } - } - }; - - const handleEdit = async (e: ChangeEvent): Promise => { - e.preventDefault(); - if (name === currName) { - toast.error(t('sameNameConflict')); - } else { - try { - await updateActionItemCategory({ - variables: { - actionItemCategoryId: categoryId, - name, - }, - }); - - setName(''); - setCategoryId(''); - refetch(); - - setModalIsOpen(false); - - toast.success(t('successfulUpdation')); - } catch (error: unknown) { - if (error instanceof Error) { - toast.error(error.message); - console.log(error.message); - } - } - } - }; - - const handleStatusChange = async ( - id: string, - disabledStatus: boolean, - ): Promise => { - try { - await updateActionItemCategory({ - variables: { - actionItemCategoryId: id, - isDisabled: !disabledStatus, - }, - }); - - refetch(); - - toast.success( - disabledStatus ? t('categoryEnabled') : t('categoryDisabled'), - ); - } catch (error: unknown) { - if (error instanceof Error) { - toast.error(error.message); - console.log(error.message); - } - } - }; - - const showCreateModal = (): void => { - setModalType('Create'); - setModalIsOpen(true); - }; - - const showUpdateModal = (name: string, id: string): void => { - setCurrName(name); - setName(name); - setCategoryId(id); - setModalType('Update'); - setModalIsOpen(true); - }; - - const hideModal = (): void => { - setName(''); - setCategoryId(''); - setModalIsOpen(false); - }; - - if (loading) { - return ; - } - - if (error) { - return ( -
    - -
    - Error occured while loading Action Item Categories Data -
    - {`${error.message}`} -
    -
    - ); - } - - const actionItemCategories = data?.actionItemCategoriesByOrganization; - - return ( - <> - - -
    - {actionItemCategories?.map((category, index) => { - return ( -
    -
    -
    - {category.name} -
    -
    - - -
    -
    - - {index !== actionItemCategories.length - 1 &&
    } -
    - ); - })} -
    - - - -

    - {t('actionItemCategoryDetails')} -

    - -
    - -
    - - {t('actionItemCategoryName')} - - { - setName(e.target.value); - }} - /> - - -
    -
    - - ); -}; - -export default OrgActionItemCategories; diff --git a/src/components/OrgActionItemCategories/OrgActionItemCategoryMocks.ts b/src/components/OrgActionItemCategories/OrgActionItemCategoryMocks.ts deleted file mode 100644 index b03e53c5f5..0000000000 --- a/src/components/OrgActionItemCategories/OrgActionItemCategoryMocks.ts +++ /dev/null @@ -1,174 +0,0 @@ -import { - CREATE_ACTION_ITEM_CATEGORY_MUTATION, - UPDATE_ACTION_ITEM_CATEGORY_MUTATION, -} from 'GraphQl/Mutations/mutations'; - -import { ACTION_ITEM_CATEGORY_LIST } from 'GraphQl/Queries/Queries'; - -export const MOCKS = [ - { - request: { - query: ACTION_ITEM_CATEGORY_LIST, - variables: { organizationId: '123' }, - }, - result: { - data: { - actionItemCategoriesByOrganization: [ - { - _id: '1', - name: 'ActionItemCategory 1', - isDisabled: false, - }, - { - _id: '2', - name: 'ActionItemCategory 2', - isDisabled: true, - }, - { - _id: '3', - name: 'ActionItemCategory 3', - isDisabled: false, - }, - ], - }, - }, - }, - { - request: { - query: CREATE_ACTION_ITEM_CATEGORY_MUTATION, - variables: { name: 'ActionItemCategory 4', organizationId: '123' }, - }, - result: { - data: { - createActionItemCategory: { - _id: '4', - }, - }, - }, - }, - { - request: { - query: UPDATE_ACTION_ITEM_CATEGORY_MUTATION, - variables: { - name: 'ActionItemCategory 1 updated', - actionItemCategoryId: '1', - }, - }, - result: { - data: { - updateActionItemCategory: { - _id: '1', - }, - }, - }, - }, - { - request: { - query: UPDATE_ACTION_ITEM_CATEGORY_MUTATION, - variables: { - isDisabled: true, - actionItemCategoryId: '1', - }, - }, - result: { - data: { - updateActionItemCategory: { - _id: '1', - }, - }, - }, - }, - { - request: { - query: UPDATE_ACTION_ITEM_CATEGORY_MUTATION, - variables: { - isDisabled: false, - actionItemCategoryId: '2', - }, - }, - result: { - data: { - updateActionItemCategory: { - _id: '2', - }, - }, - }, - }, -]; - -export const MOCKS_ERROR_QUERY = [ - { - request: { - query: ACTION_ITEM_CATEGORY_LIST, - variables: { organizationId: '123' }, - }, - error: new Error('Mock Graphql Error'), - }, -]; - -export const MOCKS_ERROR_MUTATIONS = [ - { - request: { - query: ACTION_ITEM_CATEGORY_LIST, - variables: { organizationId: '123' }, - }, - result: { - data: { - actionItemCategoriesByOrganization: [ - { - _id: '1', - name: 'ActionItemCategory 1', - isDisabled: false, - }, - { - _id: '2', - name: 'ActionItemCategory 2', - isDisabled: true, - }, - { - _id: '3', - name: 'ActionItemCategory 3', - isDisabled: false, - }, - ], - }, - }, - }, - { - request: { - query: CREATE_ACTION_ITEM_CATEGORY_MUTATION, - variables: { name: 'ActionItemCategory 4', organizationId: '123' }, - }, - error: new Error('Mock Graphql Error'), - }, - { - request: { - query: UPDATE_ACTION_ITEM_CATEGORY_MUTATION, - variables: { - name: 'ActionItemCategory 1 updated', - actionItemCategoryId: '1', - }, - }, - error: new Error('Mock Graphql Error'), - }, - { - request: { - query: UPDATE_ACTION_ITEM_CATEGORY_MUTATION, - variables: { - isDisabled: true, - actionItemCategoryId: '1', - }, - }, - error: new Error('Mock Graphql Error'), - }, - { - request: { - query: UPDATE_ACTION_ITEM_CATEGORY_MUTATION, - variables: { - isDisabled: false, - actionItemCategoryId: '2', - }, - }, - error: new Error('Mock Graphql Error'), - }, -]; diff --git a/src/components/OrgAdminListCard/OrgAdminListCard.test.tsx b/src/components/OrgAdminListCard/OrgAdminListCard.test.tsx index 282dedb330..7baea946d2 100644 --- a/src/components/OrgAdminListCard/OrgAdminListCard.test.tsx +++ b/src/components/OrgAdminListCard/OrgAdminListCard.test.tsx @@ -1,5 +1,5 @@ -import React from 'react'; -import { act, render, screen, waitFor } from '@testing-library/react'; +import React, { act } from 'react'; +import { render, screen, waitFor } from '@testing-library/react'; import type { RenderResult } from '@testing-library/react'; import { MockedProvider } from '@apollo/react-testing'; import userEvent from '@testing-library/user-event'; diff --git a/src/components/OrgAdminListCard/OrgAdminListCard.tsx b/src/components/OrgAdminListCard/OrgAdminListCard.tsx index 9afb47000d..f8fc454823 100644 --- a/src/components/OrgAdminListCard/OrgAdminListCard.tsx +++ b/src/components/OrgAdminListCard/OrgAdminListCard.tsx @@ -12,7 +12,13 @@ interface InterfaceOrgPeopleListCardProps { id: string | undefined; toggleRemoveModal: () => void; } - +/** + * Component to confirm and handle the removal of an admin. + * + * @param id - ID of the admin to be removed. + * @param toggleRemoveModal - Function to toggle the visibility of the modal. + * @returns JSX element for the removal confirmation modal. + */ function orgAdminListCard(props: InterfaceOrgPeopleListCardProps): JSX.Element { if (!props.id) { return ; @@ -25,6 +31,10 @@ function orgAdminListCard(props: InterfaceOrgPeopleListCardProps): JSX.Element { }); const { t: tCommon } = useTranslation('common'); + /** + * Function to remove the admin from the organization + * and display a success message. + */ const removeAdmin = async (): Promise => { try { const { data } = await remove({ @@ -34,7 +44,7 @@ function orgAdminListCard(props: InterfaceOrgPeopleListCardProps): JSX.Element { }, }); if (data) { - toast.success(t('adminRemoved')); + toast.success(t('adminRemoved') as string); setTimeout(() => { window.location.reload(); }, 2000); diff --git a/src/components/OrgContriCards/OrgContriCards.tsx b/src/components/OrgContriCards/OrgContriCards.tsx index 69a9e03d58..6635be09b8 100644 --- a/src/components/OrgContriCards/OrgContriCards.tsx +++ b/src/components/OrgContriCards/OrgContriCards.tsx @@ -5,6 +5,9 @@ import { useTranslation } from 'react-i18next'; import styles from './OrgContriCards.module.css'; +/** + * Props for the OrgContriCards component + */ interface InterfaceOrgContriCardsProps { key: string; id: string; @@ -14,6 +17,16 @@ interface InterfaceOrgContriCardsProps { contriTransactionId: string; userEmail: string; } + +/** + * Component to display organization contribution cards + * + * This component shows the contribution details of a user in a card format. It includes + * the user's name, email, contribution date, transaction ID, and the contribution amount. + * + * @param props - The properties passed to the component + * @returns JSX.Element representing a contribution card + */ function orgContriCards(props: InterfaceOrgContriCardsProps): JSX.Element { const { t } = useTranslation('translation', { keyPrefix: 'orgContriCards', diff --git a/src/components/OrgDelete/OrgDelete.tsx b/src/components/OrgDelete/OrgDelete.tsx index 0f1335dae4..e596445e5c 100644 --- a/src/components/OrgDelete/OrgDelete.tsx +++ b/src/components/OrgDelete/OrgDelete.tsx @@ -1,6 +1,13 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; +/** + * Component for displaying organization deletion message + * + * This component renders a message related to deleting an organization. + * + * @returns JSX.Element representing the organization deletion message + */ function orgDelete(): JSX.Element { const { t } = useTranslation('translation', { keyPrefix: 'orgDelete', @@ -8,6 +15,7 @@ function orgDelete(): JSX.Element { return ( <> + {/* Container for the organization deletion message */}
    {t('deleteOrg')}
    diff --git a/src/components/OrgListCard/OrgListCard.test.tsx b/src/components/OrgListCard/OrgListCard.test.tsx index 25d7f01ed1..4072265ea4 100644 --- a/src/components/OrgListCard/OrgListCard.test.tsx +++ b/src/components/OrgListCard/OrgListCard.test.tsx @@ -1,5 +1,5 @@ -import React from 'react'; -import { act, render, screen } from '@testing-library/react'; +import React, { act } from 'react'; +import { render, screen } from '@testing-library/react'; import 'jest-location-mock'; import { I18nextProvider } from 'react-i18next'; diff --git a/src/components/OrgListCard/OrgListCard.tsx b/src/components/OrgListCard/OrgListCard.tsx index bdba9107b0..10365d2364 100644 --- a/src/components/OrgListCard/OrgListCard.tsx +++ b/src/components/OrgListCard/OrgListCard.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { ReactComponent as FlaskIcon } from 'assets/svgs/flask.svg'; +import FlaskIcon from 'assets/svgs/flask.svg?react'; import Button from 'react-bootstrap/Button'; import { useTranslation } from 'react-i18next'; import styles from './OrgListCard.module.css'; @@ -16,20 +16,38 @@ import { useQuery } from '@apollo/client'; import { Tooltip } from '@mui/material'; import Avatar from 'components/Avatar/Avatar'; +/** + * Props for the OrgListCard component + */ export interface InterfaceOrgListCardProps { data: InterfaceOrgConnectionInfoType; } +/** + * Component for displaying a list card for an organization + * + * This component renders a card that displays information about an organization, + * including its name, address, members, and admins. It also provides a button + * to manage the organization, navigating to the organization's dashboard. + * + * @param props - The properties passed to the component + * @returns JSX.Element representing an organization list card + */ function orgListCard(props: InterfaceOrgListCardProps): JSX.Element { + // Destructure data from props const { _id, admins, image, address, members, name } = props.data; + // Query to check if the organization is a sample organization const { data } = useQuery(IS_SAMPLE_ORGANIZATION_QUERY, { variables: { isSampleOrganizationId: _id, }, }); + // Use navigate hook from react-router-dom to navigate to the organization dashboard const navigate = useNavigate(); + + // Query to get the organization list const { data: userData, }: { @@ -40,6 +58,7 @@ function orgListCard(props: InterfaceOrgListCardProps): JSX.Element { variables: { id: _id }, }); + // Handle click event to navigate to the organization dashboard function handleClick(): void { const url = '/orgdash/' + _id; @@ -54,8 +73,10 @@ function orgListCard(props: InterfaceOrgListCardProps): JSX.Element { return ( <> + {/* Container for the organization card */}
    + {/* Container for the organization image */}
    {image ? ( {`${name} @@ -68,12 +89,15 @@ function orgListCard(props: InterfaceOrgListCardProps): JSX.Element { )}
    + {/* Tooltip for the organization name */}

    {name}

    + {/* Description of the organization */}
    {userData?.organizations[0].description}
    + {/* Display the organization address if available */} {address && address.city && (
    @@ -83,17 +107,20 @@ function orgListCard(props: InterfaceOrgListCardProps): JSX.Element {
    )} + {/* Display the number of admins and members */}
    {tCommon('admins')}: {admins.length}       {tCommon('members')}: {members.length}
    + {/* Button to manage the organization */} {t('removeMemberMsg')} + {/* Button to cancel the removal action */} + {/* Button to confirm the removal action */} + + +
    + {/* Input field to enter amount to be pledged */} + + + + setFormState({ ...formState, name: e.target.value }) + } + required + /> + + + + + setFormState({ + ...formState, + isDisabled: !isDisabled, + }) + } + /> + + + +
    +
    + + ); +}; + +export default CategoryModal; diff --git a/src/components/OrgSettings/ActionItemCategories/OrgActionItemCategories.module.css b/src/components/OrgSettings/ActionItemCategories/OrgActionItemCategories.module.css new file mode 100644 index 0000000000..919421b0f2 --- /dev/null +++ b/src/components/OrgSettings/ActionItemCategories/OrgActionItemCategories.module.css @@ -0,0 +1,138 @@ +/* Button Styles */ +.addButton { + /* Position and size of the button */ + width: 7em; + position: absolute; + right: 1rem; + top: 1rem; +} + +/* Modal Styles */ +.createModal { + /* Position and size of the modal */ + margin-top: 20vh; + margin-left: 13vw; + max-width: 80vw; +} + +.icon { + /* Size and color of the icon */ + transform: scale(1.5); + color: var(--bs-danger); + margin-bottom: 1rem; +} + +.message { + /* Centering the content of the modal */ + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; +} + +.titlemodal { + /* Styling for the modal title */ + color: #707070; + font-weight: 600; + font-size: 32px; + width: 65%; + margin-bottom: 0px; +} + +.modalCloseBtn { + /* Styling for the modal close button */ + width: 40px; + height: 40px; + padding: 1rem; + display: flex; + justify-content: center; + align-items: center; +} + +/* Input Styles */ +.noOutline input { + /* Removing the outline from the input */ + outline: none; +} + +/* Header and Action Item Categories Styles */ +.btnsContainer { + /* Styling for the container of the buttons */ + display: flex; + margin: 0.5rem 0 1.5rem 0; +} + +.btnsContainer .input { + /* Styling for the input field */ + flex: 1; + min-width: 18rem; + position: relative; +} + +.btnsContainer input { + /* Styling for the input border */ + outline: 1px solid var(--bs-gray-400); +} + +.btnsContainer .input button { + /* Styling for the button in the input field */ + width: 52px; +} + +.inputField { + margin-top: 10px; + margin-bottom: 10px; + background-color: white; + box-shadow: 0 1px 1px #31bb6b; +} + +.inputField > button { + padding-top: 10px; + padding-bottom: 10px; +} + +/* Dropdown Styles */ +.dropdown { + /* Styling for the dropdown */ + background-color: white; + border: 1px solid #31bb6b; + position: relative; + display: inline-block; + color: #31bb6b; +} + +/* Datagrid Styles */ +.rowBackground { + /* Styling for the row background */ + background-color: var(--bs-white); + max-height: 120px; +} + +.tableHeader { + /* Styling for the table header */ + background-color: var(--bs-primary); + color: var(--bs-white); + font-size: 1rem; +} + +.chipIcon { + /* Styling for the chip icon */ + height: 0.9rem !important; +} + +.chip { + /* Styling for the chip */ + height: 1.5rem !important; +} + +.active { + /* Styling for the active state */ + background-color: #31bb6a50 !important; +} + +.pending { + /* Styling for the pending state */ + background-color: #ffd76950 !important; + color: #bb952bd0 !important; + border-color: #bb952bd0 !important; +} diff --git a/src/components/OrgSettings/ActionItemCategories/OrgActionItemCategories.test.tsx b/src/components/OrgSettings/ActionItemCategories/OrgActionItemCategories.test.tsx new file mode 100644 index 0000000000..d3698bf346 --- /dev/null +++ b/src/components/OrgSettings/ActionItemCategories/OrgActionItemCategories.test.tsx @@ -0,0 +1,241 @@ +import React from 'react'; +import { MockedProvider } from '@apollo/react-testing'; +import type { RenderResult } from '@testing-library/react'; +import { fireEvent, render, screen, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { I18nextProvider } from 'react-i18next'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; +import { store } from 'state/store'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import i18n from 'utils/i18nForTest'; +import type { ApolloLink } from '@apollo/client'; +import { MOCKS, MOCKS_EMPTY, MOCKS_ERROR } from './OrgActionItemCategoryMocks'; +import OrgActionItemCategories from './OrgActionItemCategories'; + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + error: jest.fn(), + }, +})); + +jest.mock('@mui/x-date-pickers/DateTimePicker', () => { + return { + DateTimePicker: jest.requireActual( + '@mui/x-date-pickers/DesktopDateTimePicker', + ).DesktopDateTimePicker, + }; +}); + +const link1 = new StaticMockLink(MOCKS); +const link2 = new StaticMockLink(MOCKS_EMPTY); +const link3 = new StaticMockLink(MOCKS_ERROR); +const t = { + ...JSON.parse( + JSON.stringify( + i18n.getDataByLanguage('en')?.translation.orgActionItemCategories ?? {}, + ), + ), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.common ?? {})), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.errors ?? {})), +}; + +const renderActionItemCategories = ( + link: ApolloLink, + orgId: string, +): RenderResult => { + return render( + + + + + + + + + , + ); +}; + +describe('Testing Organisation Action Item Categories', () => { + it('should render the Action Item Categories Screen', async () => { + renderActionItemCategories(link1, 'orgId'); + await waitFor(() => { + expect(screen.getByTestId('searchByName')).toBeInTheDocument(); + expect(screen.getByText('Category 1')).toBeInTheDocument(); + expect(screen.getByText('Category 2')).toBeInTheDocument(); + }); + }); + + it('Sort the Categories (asc/desc) by createdAt', async () => { + renderActionItemCategories(link1, 'orgId'); + + const sortBtn = await screen.findByTestId('sort'); + expect(sortBtn).toBeInTheDocument(); + + // Sort by createdAt_DESC + fireEvent.click(sortBtn); + await waitFor(() => { + expect(screen.getByTestId('createdAt_DESC')).toBeInTheDocument(); + }); + fireEvent.click(screen.getByTestId('createdAt_DESC')); + await waitFor(() => { + expect(screen.getAllByTestId('categoryName')[0]).toHaveTextContent( + 'Category 1', + ); + }); + + // Sort by createdAt_ASC + fireEvent.click(sortBtn); + await waitFor(() => { + expect(screen.getByTestId('createdAt_ASC')).toBeInTheDocument(); + }); + fireEvent.click(screen.getByTestId('createdAt_ASC')); + await waitFor(() => { + expect(screen.getAllByTestId('categoryName')[0]).toHaveTextContent( + 'Category 2', + ); + }); + }); + + it('Filter the categories by status (All/Disabled)', async () => { + renderActionItemCategories(link1, 'orgId'); + + const filterBtn = await screen.findByTestId('filter'); + expect(filterBtn).toBeInTheDocument(); + + // Filter by All + fireEvent.click(filterBtn); + await waitFor(() => { + expect(screen.getByTestId('statusAll')).toBeInTheDocument(); + }); + fireEvent.click(screen.getByTestId('statusAll')); + + await waitFor(() => { + expect(screen.getByText('Category 1')).toBeInTheDocument(); + expect(screen.getByText('Category 2')).toBeInTheDocument(); + }); + + // Filter by Disabled + fireEvent.click(filterBtn); + await waitFor(() => { + expect(screen.getByTestId('statusDisabled')).toBeInTheDocument(); + }); + fireEvent.click(screen.getByTestId('statusDisabled')); + await waitFor(() => { + expect(screen.queryByText('Category 1')).toBeNull(); + expect(screen.getByText('Category 2')).toBeInTheDocument(); + }); + }); + + it('Filter the categories by status (Active)', async () => { + renderActionItemCategories(link1, 'orgId'); + + const filterBtn = await screen.findByTestId('filter'); + expect(filterBtn).toBeInTheDocument(); + + fireEvent.click(filterBtn); + await waitFor(() => { + expect(screen.getByTestId('statusActive')).toBeInTheDocument(); + }); + fireEvent.click(screen.getByTestId('statusActive')); + await waitFor(() => { + expect(screen.getByText('Category 1')).toBeInTheDocument(); + expect(screen.queryByText('Category 2')).toBeNull(); + }); + }); + + it('open and closes Create Category modal', async () => { + renderActionItemCategories(link1, 'orgId'); + + const addCategoryBtn = await screen.findByTestId( + 'createActionItemCategoryBtn', + ); + expect(addCategoryBtn).toBeInTheDocument(); + userEvent.click(addCategoryBtn); + + await waitFor(() => expect(screen.getAllByText(t.create)).toHaveLength(2)); + userEvent.click(screen.getByTestId('actionItemCategoryModalCloseBtn')); + await waitFor(() => + expect( + screen.queryByTestId('actionItemCategoryModalCloseBtn'), + ).toBeNull(), + ); + }); + + it('open and closes Edit Category modal', async () => { + renderActionItemCategories(link1, 'orgId'); + + const editCategoryBtn = await screen.findByTestId('editCategoryBtn1'); + await waitFor(() => expect(editCategoryBtn).toBeInTheDocument()); + userEvent.click(editCategoryBtn); + + await waitFor(() => + expect(screen.getByText(t.updateActionItemCategory)).toBeInTheDocument(), + ); + userEvent.click(screen.getByTestId('actionItemCategoryModalCloseBtn')); + await waitFor(() => + expect( + screen.queryByTestId('actionItemCategoryModalCloseBtn'), + ).toBeNull(), + ); + }); + + it('Search categories by name', async () => { + renderActionItemCategories(link1, 'orgId'); + + const searchInput = await screen.findByTestId('searchByName'); + expect(searchInput).toBeInTheDocument(); + + userEvent.type(searchInput, 'Category 1'); + userEvent.click(screen.getByTestId('searchBtn')); + await waitFor(() => { + expect(screen.getByText('Category 1')).toBeInTheDocument(); + expect(screen.queryByText('Category 2')).toBeNull(); + }); + }); + + it('Search categories by name and clear the input by backspace', async () => { + renderActionItemCategories(link1, 'orgId'); + + const searchInput = await screen.findByTestId('searchByName'); + expect(searchInput).toBeInTheDocument(); + + // Clear the search input by backspace + userEvent.type(searchInput, 'A{backspace}'); + await waitFor(() => { + expect(screen.getByText('Category 1')).toBeInTheDocument(); + expect(screen.getByText('Category 2')).toBeInTheDocument(); + }); + }); + + it('Search categories by name on press of ENTER', async () => { + renderActionItemCategories(link1, 'orgId'); + + const searchInput = await screen.findByTestId('searchByName'); + expect(searchInput).toBeInTheDocument(); + + userEvent.type(searchInput, 'Category 1'); + userEvent.type(searchInput, '{enter}'); + await waitFor(() => { + expect(screen.getByText('Category 1')).toBeInTheDocument(); + expect(screen.queryByText('Category 2')).toBeNull(); + }); + }); + + it('should render Empty Action Item Categories Screen', async () => { + renderActionItemCategories(link2, 'orgId'); + await waitFor(() => { + expect(screen.getByTestId('searchByName')).toBeInTheDocument(); + expect(screen.getByText(t.noActionItemCategories)).toBeInTheDocument(); + }); + }); + + it('should render the Action Item Categories Screen with error', async () => { + renderActionItemCategories(link3, 'orgId'); + await waitFor(() => { + expect(screen.getByTestId('errorMsg')).toBeInTheDocument(); + }); + }); +}); diff --git a/src/components/OrgSettings/ActionItemCategories/OrgActionItemCategories.tsx b/src/components/OrgSettings/ActionItemCategories/OrgActionItemCategories.tsx new file mode 100644 index 0000000000..49cf47dd49 --- /dev/null +++ b/src/components/OrgSettings/ActionItemCategories/OrgActionItemCategories.tsx @@ -0,0 +1,418 @@ +import type { FC } from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; +import { Button, Dropdown, Form } from 'react-bootstrap'; +import styles from './OrgActionItemCategories.module.css'; +import { useTranslation } from 'react-i18next'; + +import { useQuery } from '@apollo/client'; +import { ACTION_ITEM_CATEGORY_LIST } from 'GraphQl/Queries/Queries'; +import type { InterfaceActionItemCategoryInfo } from 'utils/interfaces'; +import Loader from 'components/Loader/Loader'; +import { + Circle, + Search, + Sort, + WarningAmberRounded, + FilterAltOutlined, +} from '@mui/icons-material'; +import { + DataGrid, + type GridCellParams, + type GridColDef, +} from '@mui/x-data-grid'; +import dayjs from 'dayjs'; +import { Chip, Stack } from '@mui/material'; +import CategoryModal from './CategoryModal'; + +enum ModalState { + SAME = 'same', + DELETE = 'delete', +} + +enum CategoryStatus { + Active = 'active', + Disabled = 'disabled', +} + +interface InterfaceActionItemCategoryProps { + orgId: string; +} + +const dataGridStyle = { + '&.MuiDataGrid-root .MuiDataGrid-cell:focus-within': { + outline: 'none !important', + }, + '&.MuiDataGrid-root .MuiDataGrid-columnHeader:focus-within': { + outline: 'none', + }, + '& .MuiDataGrid-row:hover': { + backgroundColor: 'transparent', + }, + '& .MuiDataGrid-row.Mui-hovered': { + backgroundColor: 'transparent', + }, + '& .MuiDataGrid-root': { + borderRadius: '0.5rem', + }, + '& .MuiDataGrid-main': { + borderRadius: '0.5rem', + }, +}; + +/** + * Represents the component for managing organization action item categories. + * This component allows creating, updating, enabling, and disabling action item categories. + */ +const OrgActionItemCategories: FC = ({ + orgId, +}) => { + const { t } = useTranslation('translation', { + keyPrefix: 'orgActionItemCategories', + }); + const { t: tCommon } = useTranslation('common'); + const { t: tErrors } = useTranslation('errors'); + + const [category, setCategory] = + useState(null); + const [searchTerm, setSearchTerm] = useState(''); + const [searchValue, setSearchValue] = useState(''); + const [sortBy, setSortBy] = useState<'createdAt_ASC' | 'createdAt_DESC'>( + 'createdAt_DESC', + ); + const [status, setStatus] = useState(null); + const [categories, setCategories] = useState< + InterfaceActionItemCategoryInfo[] + >([]); + const [modalMode, setModalMode] = useState<'edit' | 'create'>('create'); + const [modalState, setModalState] = useState<{ + [key in ModalState]: boolean; + }>({ + [ModalState.SAME]: false, + [ModalState.DELETE]: false, + }); + + // Query to fetch action item categories + const { + data: catData, + loading: catLoading, + error: catError, + refetch: refetchCategories, + }: { + data?: { + actionItemCategoriesByOrganization: InterfaceActionItemCategoryInfo[]; + }; + loading: boolean; + error?: Error | undefined; + refetch: () => void; + } = useQuery(ACTION_ITEM_CATEGORY_LIST, { + variables: { + organizationId: orgId, + where: { + name_contains: searchTerm, + is_disabled: !status ? undefined : status === CategoryStatus.Disabled, + }, + orderBy: sortBy, + }, + }); + + const openModal = (modal: ModalState): void => + setModalState((prevState) => ({ ...prevState, [modal]: true })); + + const closeModal = (modal: ModalState): void => + setModalState((prevState) => ({ ...prevState, [modal]: false })); + + const handleOpenModal = useCallback( + ( + category: InterfaceActionItemCategoryInfo | null, + mode: 'edit' | 'create', + ): void => { + setCategory(category); + setModalMode(mode); + openModal(ModalState.SAME); + }, + [openModal], + ); + + useEffect(() => { + if (catData && catData.actionItemCategoriesByOrganization) { + setCategories(catData.actionItemCategoriesByOrganization); + } + }, [catData]); + + // Show loader while data is being fetched + if (catLoading) { + return ; + } + + // Show error message if there's an error + if (catError) { + return ( +
    + +
    + {tErrors('errorLoading', { entity: 'Action Item Categories' })} +
    + {`${catError.message}`} +
    +
    + ); + } + + const columns: GridColDef[] = [ + { + field: 'id', + headerName: 'Sr. No.', + flex: 1, + minWidth: 100, + align: 'center', + headerAlign: 'center', + headerClassName: `${styles.tableHeader}`, + sortable: false, + renderCell: (params: GridCellParams) => { + return
    {params.row.id}
    ; + }, + }, + { + field: 'categoryName', + headerName: 'Category', + flex: 2, + align: 'center', + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + return ( +
    + {params.row.name} +
    + ); + }, + }, + { + field: 'status', + headerName: 'Status', + flex: 1, + align: 'center', + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + return ( + } + label={params.row.isDisabled ? 'Disabled' : 'Active'} + variant="outlined" + color="primary" + className={`${styles.chip} ${params.row.isDisabled ? styles.pending : styles.active}`} + /> + ); + }, + }, + { + field: 'createdBy', + headerName: 'Created By', + flex: 1, + align: 'center', + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + return params.row.creator.firstName + ' ' + params.row.creator.lastName; + }, + }, + { + field: 'createdOn', + headerName: 'Created On', + align: 'center', + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + flex: 1, + renderCell: (params: GridCellParams) => { + return ( +
    + {dayjs(params.row.createdAt).format('DD/MM/YYYY')} +
    + ); + }, + }, + { + field: 'action', + headerName: 'Action', + flex: 2, + align: 'center', + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + return ( + + ); + }, + }, + ]; + + return ( +
    + {/* Header with search, filter and Create Button */} +
    +
    + setSearchValue(e.target.value)} + onKeyUp={(e) => { + if (e.key === 'Enter') { + setSearchTerm(searchValue); + } else if (e.key === 'Backspace' && searchValue === '') { + setSearchTerm(''); + } + }} + data-testid="searchByName" + /> + +
    +
    +
    + + + + {tCommon('sort')} + + + setSortBy('createdAt_DESC')} + data-testid="createdAt_DESC" + > + {tCommon('createdLatest')} + + setSortBy('createdAt_ASC')} + data-testid="createdAt_ASC" + > + {tCommon('createdEarliest')} + + + + + + + {t('status')} + + + setStatus(null)} + data-testid="statusAll" + > + {tCommon('all')} + + setStatus(CategoryStatus.Active)} + data-testid="statusActive" + > + {tCommon('active')} + + setStatus(CategoryStatus.Disabled)} + data-testid="statusDisabled" + > + {tCommon('disabled')} + + + +
    +
    + +
    +
    +
    + + {/* Table with Action Item Categories */} + row._id} + slots={{ + noRowsOverlay: () => ( + + {t('noActionItemCategories')} + + ), + }} + sx={dataGridStyle} + getRowClassName={() => `${styles.rowBackground}`} + autoHeight + rowHeight={65} + rows={categories.map((category, index) => ({ + id: index + 1, + ...category, + }))} + columns={columns} + isRowSelectable={() => false} + /> + + closeModal(ModalState.SAME)} + refetchCategories={refetchCategories} + category={category} + orgId={orgId} + mode={modalMode} + /> +
    + ); +}; + +export default OrgActionItemCategories; diff --git a/src/components/OrgSettings/ActionItemCategories/OrgActionItemCategoryMocks.ts b/src/components/OrgSettings/ActionItemCategories/OrgActionItemCategoryMocks.ts new file mode 100644 index 0000000000..10310a01e4 --- /dev/null +++ b/src/components/OrgSettings/ActionItemCategories/OrgActionItemCategoryMocks.ts @@ -0,0 +1,288 @@ +import { + CREATE_ACTION_ITEM_CATEGORY_MUTATION, + UPDATE_ACTION_ITEM_CATEGORY_MUTATION, +} from 'GraphQl/Mutations/mutations'; + +import { ACTION_ITEM_CATEGORY_LIST } from 'GraphQl/Queries/Queries'; + +export const MOCKS = [ + { + request: { + query: ACTION_ITEM_CATEGORY_LIST, + variables: { + organizationId: 'orgId', + where: { name_contains: '' }, + orderBy: 'createdAt_DESC', + }, + }, + result: { + data: { + actionItemCategoriesByOrganization: [ + { + _id: 'categoryId1', + name: 'Category 1', + isDisabled: false, + createdAt: '2024-08-26', + creator: { + _id: 'creatorId1', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + }, + { + _id: 'categoryId2', + name: 'Category 2', + isDisabled: true, + createdAt: '2024-08-25', + creator: { + _id: 'creatorId2', + firstName: 'John', + lastName: 'Doe', + }, + }, + ], + }, + }, + }, + { + request: { + query: ACTION_ITEM_CATEGORY_LIST, + variables: { + organizationId: 'orgId', + where: { name_contains: '' }, + orderBy: 'createdAt_ASC', + }, + }, + result: { + data: { + actionItemCategoriesByOrganization: [ + { + _id: 'categoryId2', + name: 'Category 2', + isDisabled: true, + createdAt: '2024-08-25', + creator: { + _id: 'creatorId2', + firstName: 'John', + lastName: 'Doe', + }, + }, + { + _id: 'categoryId1', + name: 'Category 1', + isDisabled: false, + createdAt: '2024-08-26', + creator: { + _id: 'creatorId1', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + }, + ], + }, + }, + }, + { + request: { + query: ACTION_ITEM_CATEGORY_LIST, + variables: { + organizationId: 'orgId', + where: { name_contains: '', is_disabled: false }, + orderBy: 'createdAt_DESC', + }, + }, + result: { + data: { + actionItemCategoriesByOrganization: [ + { + _id: 'categoryId1', + name: 'Category 1', + isDisabled: false, + createdAt: '2024-08-26', + creator: { + _id: 'creatorId1', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + }, + ], + }, + }, + }, + { + request: { + query: ACTION_ITEM_CATEGORY_LIST, + variables: { + organizationId: 'orgId', + where: { name_contains: '', is_disabled: true }, + orderBy: 'createdAt_DESC', + }, + }, + result: { + data: { + actionItemCategoriesByOrganization: [ + { + _id: 'categoryId2', + name: 'Category 2', + isDisabled: true, + createdAt: '2024-08-25', + creator: { + _id: 'creatorId2', + firstName: 'John', + lastName: 'Doe', + }, + }, + ], + }, + }, + }, + { + request: { + query: ACTION_ITEM_CATEGORY_LIST, + variables: { + organizationId: 'orgId', + where: { name_contains: 'Category 1' }, + orderBy: 'createdAt_DESC', + }, + }, + result: { + data: { + actionItemCategoriesByOrganization: [ + { + _id: 'categoryId1', + name: 'Category 1', + isDisabled: false, + createdAt: '2024-08-26', + creator: { + _id: 'creatorId1', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + }, + ], + }, + }, + }, + { + request: { + query: CREATE_ACTION_ITEM_CATEGORY_MUTATION, + variables: { + name: 'Category 2', + isDisabled: true, + organizationId: 'orgId', + }, + }, + result: { + data: { + createActionItemCategory: { + _id: 'categoryId3', + }, + }, + }, + }, + { + request: { + query: UPDATE_ACTION_ITEM_CATEGORY_MUTATION, + variables: { + name: 'Category 2', + isDisabled: true, + actionItemCategoryId: 'categoryId', + }, + }, + result: { + data: { + updateActionItemCategory: { + _id: 'categoryId', + }, + }, + }, + }, + { + request: { + query: UPDATE_ACTION_ITEM_CATEGORY_MUTATION, + variables: { + name: 'Category 2', + isDisabled: false, + actionItemCategoryId: 'categoryId', + }, + }, + result: { + data: { + updateActionItemCategory: { + _id: 'categoryId', + }, + }, + }, + }, + { + request: { + query: UPDATE_ACTION_ITEM_CATEGORY_MUTATION, + variables: { + name: 'Category 1', + isDisabled: true, + actionItemCategoryId: 'categoryId', + }, + }, + result: { + data: { + updateActionItemCategory: { + _id: 'categoryId', + }, + }, + }, + }, +]; + +export const MOCKS_EMPTY = [ + { + request: { + query: ACTION_ITEM_CATEGORY_LIST, + variables: { + organizationId: 'orgId', + where: { name_contains: '' }, + orderBy: 'createdAt_DESC', + }, + }, + result: { + data: { + actionItemCategoriesByOrganization: [], + }, + }, + }, +]; + +export const MOCKS_ERROR = [ + { + request: { + query: ACTION_ITEM_CATEGORY_LIST, + variables: { + organizationId: 'orgId', + where: { name_contains: '' }, + orderBy: 'createdAt_DESC', + }, + }, + error: new Error('Mock Graphql Error'), + }, + { + request: { + query: CREATE_ACTION_ITEM_CATEGORY_MUTATION, + variables: { + name: 'Category 2', + isDisabled: true, + organizationId: 'orgId', + }, + }, + error: new Error('Mock Graphql Error'), + }, + { + request: { + query: UPDATE_ACTION_ITEM_CATEGORY_MUTATION, + variables: { + name: 'Category 2', + isDisabled: true, + actionItemCategoryId: 'categoryId', + }, + }, + error: new Error('Mock Graphql Error'), + }, +]; diff --git a/src/screens/OrganizationAgendaCategory/AgendaCategoryCreateModal.test.tsx b/src/components/OrgSettings/AgendaItemCategories/AgendaCategoryCreateModal.test.tsx similarity index 100% rename from src/screens/OrganizationAgendaCategory/AgendaCategoryCreateModal.test.tsx rename to src/components/OrgSettings/AgendaItemCategories/AgendaCategoryCreateModal.test.tsx diff --git a/src/screens/OrganizationAgendaCategory/AgendaCategoryCreateModal.tsx b/src/components/OrgSettings/AgendaItemCategories/AgendaCategoryCreateModal.tsx similarity index 77% rename from src/screens/OrganizationAgendaCategory/AgendaCategoryCreateModal.tsx rename to src/components/OrgSettings/AgendaItemCategories/AgendaCategoryCreateModal.tsx index 9b260d877f..57a3057b3f 100644 --- a/src/screens/OrganizationAgendaCategory/AgendaCategoryCreateModal.tsx +++ b/src/components/OrgSettings/AgendaItemCategories/AgendaCategoryCreateModal.tsx @@ -3,12 +3,18 @@ import { Modal, Form, Button } from 'react-bootstrap'; import type { ChangeEvent } from 'react'; import styles from './OrganizationAgendaCategory.module.css'; +/** + * InterfaceFormStateType is an object containing the form state + */ interface InterfaceFormStateType { name: string; description: string; createdBy: string; } +/** + * InterfaceAgendaCategoryCreateModalProps is an object containing the props for AgendaCategoryCreateModal component + */ interface InterfaceAgendaCategoryCreateModalProps { agendaCategoryCreateModalIsOpen: boolean; hideCreateModal: () => void; @@ -20,6 +26,16 @@ interface InterfaceAgendaCategoryCreateModalProps { t: (key: string) => string; } +/** + * AgendaCategoryCreateModal component is used to create the agenda category details like name, description + * @param agendaCategoryCreateModalIsOpen - boolean value to check if the modal is open or not + * @param hideCreateModal - function to hide the modal + * @param formState - object containing the form state + * @param setFormState - function to set the form state + * @param createAgendaCategoryHandler - function to create the agenda category + * @param t - i18n function to translate the text + * @returns returns the AgendaCategoryCreateModal component + */ const AgendaCategoryCreateModal: React.FC< InterfaceAgendaCategoryCreateModalProps > = ({ diff --git a/src/screens/OrganizationAgendaCategory/AgendaCategoryDeleteModal.tsx b/src/components/OrgSettings/AgendaItemCategories/AgendaCategoryDeleteModal.tsx similarity index 73% rename from src/screens/OrganizationAgendaCategory/AgendaCategoryDeleteModal.tsx rename to src/components/OrgSettings/AgendaItemCategories/AgendaCategoryDeleteModal.tsx index f2edb8fc62..a16186bac7 100644 --- a/src/screens/OrganizationAgendaCategory/AgendaCategoryDeleteModal.tsx +++ b/src/components/OrgSettings/AgendaItemCategories/AgendaCategoryDeleteModal.tsx @@ -2,6 +2,9 @@ import React from 'react'; import { Modal, Button } from 'react-bootstrap'; import styles from './OrganizationAgendaCategory.module.css'; +/** + * InterfaceAgendaCategoryDeleteModalProps is an object containing the props for AgendaCategoryDeleteModal component + */ interface InterfaceAgendaCategoryDeleteModalProps { agendaCategoryDeleteModalIsOpen: boolean; toggleDeleteModal: () => void; @@ -10,6 +13,15 @@ interface InterfaceAgendaCategoryDeleteModalProps { tCommon: (key: string) => string; } +/** + * AgendaCategoryDeleteModal component is used to delete the agenda category + * @param agendaCategoryDeleteModalIsOpen - boolean value to check if the modal is open or not + * @param toggleDeleteModal - function to toggle the modal + * @param deleteAgendaCategoryHandler - function to delete the agenda category + * @param t - i18n function to translate the text + * @param tCommon - i18n function to translate the text + * @returns returns the AgendaCategoryDeleteModal component + */ const AgendaCategoryDeleteModal: React.FC< InterfaceAgendaCategoryDeleteModalProps > = ({ diff --git a/src/screens/OrganizationAgendaCategory/AgendaCategoryPreviewModal.tsx b/src/components/OrgSettings/AgendaItemCategories/AgendaCategoryPreviewModal.tsx similarity index 76% rename from src/screens/OrganizationAgendaCategory/AgendaCategoryPreviewModal.tsx rename to src/components/OrgSettings/AgendaItemCategories/AgendaCategoryPreviewModal.tsx index c9dc17e56f..794db27ad3 100644 --- a/src/screens/OrganizationAgendaCategory/AgendaCategoryPreviewModal.tsx +++ b/src/components/OrgSettings/AgendaItemCategories/AgendaCategoryPreviewModal.tsx @@ -3,12 +3,18 @@ import { Modal, Form, Button } from 'react-bootstrap'; import styles from './OrganizationAgendaCategory.module.css'; +/** + * InterfaceFormStateType is an object containing the form state + */ interface InterfaceFormStateType { name: string; description: string; createdBy: string; } +/** + * InterfaceAgendaCategoryPreviewModalProps is an object containing the props for AgendaCategoryPreviewModal component + */ interface InterfaceAgendaCategoryPreviewModalProps { agendaCategoryPreviewModalIsOpen: boolean; hidePreviewModal: () => void; @@ -19,6 +25,16 @@ interface InterfaceAgendaCategoryPreviewModalProps { t: (key: string) => string; } +/** + * AgendaCategoryPreviewModal component is used to preview the agenda category details like name, description, createdBy + * @param agendaCategoryPreviewModalIsOpen - boolean value to check if the modal is open or not + * @param hidePreviewModal - function to hide the modal + * @param showUpdateModal - function to show the update modal + * @param toggleDeleteModal - function to toggle the delete modal + * @param formState - object containing the form state + * @param t - i18n function to translate the text + * @returns returns the AgendaCategoryPreviewModal component + */ const AgendaCategoryPreviewModal: React.FC< InterfaceAgendaCategoryPreviewModalProps > = ({ diff --git a/src/screens/OrganizationAgendaCategory/AgendaCategoryUpdateModal.test.tsx b/src/components/OrgSettings/AgendaItemCategories/AgendaCategoryUpdateModal.test.tsx similarity index 100% rename from src/screens/OrganizationAgendaCategory/AgendaCategoryUpdateModal.test.tsx rename to src/components/OrgSettings/AgendaItemCategories/AgendaCategoryUpdateModal.test.tsx diff --git a/src/screens/OrganizationAgendaCategory/AgendaCategoryUpdateModal.tsx b/src/components/OrgSettings/AgendaItemCategories/AgendaCategoryUpdateModal.tsx similarity index 76% rename from src/screens/OrganizationAgendaCategory/AgendaCategoryUpdateModal.tsx rename to src/components/OrgSettings/AgendaItemCategories/AgendaCategoryUpdateModal.tsx index 868205c339..508f1db69b 100644 --- a/src/screens/OrganizationAgendaCategory/AgendaCategoryUpdateModal.tsx +++ b/src/components/OrgSettings/AgendaItemCategories/AgendaCategoryUpdateModal.tsx @@ -4,12 +4,18 @@ import type { ChangeEvent } from 'react'; import styles from './OrganizationAgendaCategory.module.css'; +/** + * InterfaceFormStateType is an object containing the form state + */ interface InterfaceFormStateType { name: string; description: string; createdBy: string; } +/** + * InterfaceAgendaCategoryUpdateModalProps is an object containing the props for AgendaCategoryUpdateModal component + */ interface InterfaceAgendaCategoryUpdateModalProps { agendaCategoryUpdateModalIsOpen: boolean; hideUpdateModal: () => void; @@ -21,6 +27,16 @@ interface InterfaceAgendaCategoryUpdateModalProps { t: (key: string) => string; } +/** + * AgendaCategoryUpdateModal component is used to update the agenda category details like name, description + * @param agendaCategoryUpdateModalIsOpen - boolean value to check if the modal is open or not + * @param hideUpdateModal - function to hide the modal + * @param formState - object containing the form state + * @param setFormState - function to set the form state + * @param updateAgendaCategoryHandler - function to update the agenda category + * @param t - i18n function to translate the text + * @returns returns the AgendaCategoryUpdateModal component + */ const AgendaCategoryUpdateModal: React.FC< InterfaceAgendaCategoryUpdateModalProps > = ({ diff --git a/src/screens/OrganizationAgendaCategory/OrganizationAgendaCategory.module.css b/src/components/OrgSettings/AgendaItemCategories/OrganizationAgendaCategory.module.css similarity index 100% rename from src/screens/OrganizationAgendaCategory/OrganizationAgendaCategory.module.css rename to src/components/OrgSettings/AgendaItemCategories/OrganizationAgendaCategory.module.css diff --git a/src/screens/OrganizationAgendaCategory/OrganizationAgendaCategory.test.tsx b/src/components/OrgSettings/AgendaItemCategories/OrganizationAgendaCategory.test.tsx similarity index 96% rename from src/screens/OrganizationAgendaCategory/OrganizationAgendaCategory.test.tsx rename to src/components/OrgSettings/AgendaItemCategories/OrganizationAgendaCategory.test.tsx index 732db13a74..e05edc665d 100644 --- a/src/screens/OrganizationAgendaCategory/OrganizationAgendaCategory.test.tsx +++ b/src/components/OrgSettings/AgendaItemCategories/OrganizationAgendaCategory.test.tsx @@ -76,7 +76,7 @@ describe('Testing Agenda Categories Component', () => { - {} + {} @@ -96,7 +96,7 @@ describe('Testing Agenda Categories Component', () => { - {} + {} @@ -119,7 +119,7 @@ describe('Testing Agenda Categories Component', () => { - {} + {} @@ -152,7 +152,7 @@ describe('Testing Agenda Categories Component', () => { - {} + {} diff --git a/src/screens/OrganizationAgendaCategory/OrganizationAgendaCategory.tsx b/src/components/OrgSettings/AgendaItemCategories/OrganizationAgendaCategory.tsx similarity index 78% rename from src/screens/OrganizationAgendaCategory/OrganizationAgendaCategory.tsx rename to src/components/OrgSettings/AgendaItemCategories/OrganizationAgendaCategory.tsx index 4216d309a2..884371d862 100644 --- a/src/screens/OrganizationAgendaCategory/OrganizationAgendaCategory.tsx +++ b/src/components/OrgSettings/AgendaItemCategories/OrganizationAgendaCategory.tsx @@ -1,8 +1,7 @@ import React, { useState } from 'react'; -import type { ChangeEvent } from 'react'; +import type { ChangeEvent, FC } from 'react'; import { useTranslation } from 'react-i18next'; import { Button } from 'react-bootstrap'; -import { useParams } from 'react-router-dom'; import { WarningAmberRounded } from '@mui/icons-material'; import { toast } from 'react-toastify'; @@ -17,13 +16,26 @@ import AgendaCategoryCreateModal from './AgendaCategoryCreateModal'; import styles from './OrganizationAgendaCategory.module.css'; import Loader from 'components/Loader/Loader'; -function organizationAgendaCategory(): JSX.Element { +interface InterfaceAgendaCategoryProps { + orgId: string; +} + +/** + * Component for managing and displaying agenda item categories within an organization. + * + * This component allows users to view, create, and manage agenda item categories. It includes functionality for displaying categories, handling creation, and managing modal visibility. + * + * @returns The rendered component. + */ + +const organizationAgendaCategory: FC = ({ + orgId, +}) => { const { t } = useTranslation('translation', { keyPrefix: 'organizationAgendaCategory', }); - const { orgId: currentUrl } = useParams(); - + // State for managing modal visibility and form data const [agendaCategoryCreateModalIsOpen, setAgendaCategoryCreateModalIsOpen] = useState(false); @@ -33,6 +45,9 @@ function organizationAgendaCategory(): JSX.Element { createdBy: '', }); + /** + * Query to fetch agenda item categories for the organization. + */ const { data: agendaCategoryData, loading: agendaCategoryLoading, @@ -44,14 +59,23 @@ function organizationAgendaCategory(): JSX.Element { error?: unknown | undefined; refetch: () => void; } = useQuery(AGENDA_ITEM_CATEGORY_LIST, { - variables: { organizationId: currentUrl }, + variables: { organizationId: orgId }, notifyOnNetworkStatusChange: true, }); + /** + * Mutation to create a new agenda item category. + */ const [createAgendaCategory] = useMutation( CREATE_AGENDA_ITEM_CATEGORY_MUTATION, ); + /** + * Handler function to create a new agenda item category. + * + * @param e - The form submit event. + * @returns A promise that resolves when the agenda item category is created. + */ const createAgendaCategoryHandler = async ( e: ChangeEvent, ): Promise => { @@ -60,13 +84,13 @@ function organizationAgendaCategory(): JSX.Element { await createAgendaCategory({ variables: { input: { - organizationId: currentUrl, + organizationId: orgId, name: formState.name, description: formState.description, }, }, }); - toast.success(t('agendaCategoryCreated')); + toast.success(t('agendaCategoryCreated') as string); setFormState({ name: '', description: '', createdBy: '' }); refetchAgendaCategory(); hideCreateModal(); @@ -77,10 +101,16 @@ function organizationAgendaCategory(): JSX.Element { } }; + /** + * Toggles the visibility of the create agenda item category modal. + */ const showCreateModal = (): void => { setAgendaCategoryCreateModalIsOpen(!agendaCategoryCreateModalIsOpen); }; + /** + * Hides the create agenda item category modal. + */ const hideCreateModal = (): void => { setAgendaCategoryCreateModalIsOpen(!agendaCategoryCreateModalIsOpen); }; @@ -105,7 +135,7 @@ function organizationAgendaCategory(): JSX.Element { } return ( -
    +
    @@ -152,6 +182,6 @@ function organizationAgendaCategory(): JSX.Element { />
    ); -} +}; export default organizationAgendaCategory; diff --git a/src/screens/OrganizationAgendaCategory/OrganizationAgendaCategoryErrorMocks.ts b/src/components/OrgSettings/AgendaItemCategories/OrganizationAgendaCategoryErrorMocks.ts similarity index 100% rename from src/screens/OrganizationAgendaCategory/OrganizationAgendaCategoryErrorMocks.ts rename to src/components/OrgSettings/AgendaItemCategories/OrganizationAgendaCategoryErrorMocks.ts diff --git a/src/screens/OrganizationAgendaCategory/OrganizationAgendaCategoryMocks.ts b/src/components/OrgSettings/AgendaItemCategories/OrganizationAgendaCategoryMocks.ts similarity index 100% rename from src/screens/OrganizationAgendaCategory/OrganizationAgendaCategoryMocks.ts rename to src/components/OrgSettings/AgendaItemCategories/OrganizationAgendaCategoryMocks.ts diff --git a/src/components/DeleteOrg/DeleteOrg.module.css b/src/components/OrgSettings/General/DeleteOrg/DeleteOrg.module.css similarity index 100% rename from src/components/DeleteOrg/DeleteOrg.module.css rename to src/components/OrgSettings/General/DeleteOrg/DeleteOrg.module.css diff --git a/src/components/OrgSettings/General/DeleteOrg/DeleteOrg.test.tsx b/src/components/OrgSettings/General/DeleteOrg/DeleteOrg.test.tsx new file mode 100644 index 0000000000..77ffe65c08 --- /dev/null +++ b/src/components/OrgSettings/General/DeleteOrg/DeleteOrg.test.tsx @@ -0,0 +1,307 @@ +import React, { act } from 'react'; +import { MockedProvider } from '@apollo/react-testing'; +import { render, screen, waitFor } from '@testing-library/react'; +import 'jest-location-mock'; +import { I18nextProvider } from 'react-i18next'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; + +import { + DELETE_ORGANIZATION_MUTATION, + REMOVE_SAMPLE_ORGANIZATION_MUTATION, +} from 'GraphQl/Mutations/mutations'; +import { store } from 'state/store'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import i18nForTest from 'utils/i18nForTest'; +import DeleteOrg from './DeleteOrg'; +import { ToastContainer, toast } from 'react-toastify'; +import { IS_SAMPLE_ORGANIZATION_QUERY } from 'GraphQl/Queries/Queries'; +import useLocalStorage from 'utils/useLocalstorage'; + +const { setItem } = useLocalStorage(); + +async function wait(ms = 1000): Promise { + await act(async () => { + await new Promise((resolve) => setTimeout(resolve, ms)); + }); +} + +const MOCKS = [ + { + request: { + query: IS_SAMPLE_ORGANIZATION_QUERY, + variables: { + isSampleOrganizationId: '123', + }, + }, + result: { + data: { + isSampleOrganization: true, + }, + }, + }, + { + request: { + query: REMOVE_SAMPLE_ORGANIZATION_MUTATION, + }, + result: { + data: { + removeSampleOrganization: true, + }, + }, + }, + { + request: { + query: DELETE_ORGANIZATION_MUTATION, + variables: { + id: '456', + }, + }, + result: { + data: { + removeOrganization: { + _id: '456', + }, + }, + }, + }, +]; + +const MOCKS_WITH_ERROR = [ + { + request: { + query: IS_SAMPLE_ORGANIZATION_QUERY, + variables: { + isSampleOrganizationId: '123', + }, + }, + result: { + data: { + isSampleOrganization: true, + }, + }, + }, + { + request: { + query: DELETE_ORGANIZATION_MUTATION, + variables: { + id: '456', + }, + }, + error: new Error('Failed to delete organization'), + }, + { + request: { + query: REMOVE_SAMPLE_ORGANIZATION_MUTATION, + }, + error: new Error('Failed to delete sample organization'), + }, +]; + +const mockNavgatePush = jest.fn(); +let mockURL = '123'; +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: mockURL }), + useNavigate: () => mockNavgatePush, +})); + +const link = new StaticMockLink(MOCKS, true); +const link2 = new StaticMockLink(MOCKS_WITH_ERROR, true); + +afterEach(() => { + localStorage.clear(); +}); + +describe('Delete Organization Component', () => { + test('should be able to Toggle Delete Organization Modal', async () => { + mockURL = '456'; + setItem('SuperAdmin', true); + await act(async () => { + render( + + + + + + + + + + , + ); + }); + act(() => { + screen.getByTestId(/openDeleteModalBtn/i).click(); + }); + expect(await screen.findByTestId(/orgDeleteModal/i)).toBeInTheDocument(); + act(() => { + screen.getByTestId(/closeDelOrgModalBtn/i).click(); + }); + await waitFor(() => { + expect(screen.queryByTestId(/orgDeleteModal/i)).not.toBeInTheDocument(); + }); + }); + + test('should be able to Toggle Delete Organization Modal When Organization is Sample Organization', async () => { + mockURL = '123'; + setItem('SuperAdmin', true); + await act(async () => { + render( + + + + + + + + + + , + ); + }); + await wait(); + act(() => { + screen.getByTestId(/openDeleteModalBtn/i).click(); + }); + expect(screen.getByTestId(/orgDeleteModal/i)).toBeInTheDocument(); + act(() => { + screen.getByTestId(/closeDelOrgModalBtn/i).click(); + }); + await waitFor(() => { + expect(screen.queryByTestId(/orgDeleteModal/i)).not.toBeInTheDocument(); + }); + }); + + test('Delete organization functionality should work properly', async () => { + mockURL = '456'; + setItem('SuperAdmin', true); + await act(async () => { + render( + + + + + + + + + , + ); + }); + screen.debug(); + act(() => { + screen.getByTestId('openDeleteModalBtn').click(); + }); + screen.debug(); + expect(await screen.findByTestId('orgDeleteModal')).toBeInTheDocument(); + const deleteButton = await screen.findByTestId('deleteOrganizationBtn'); + act(() => { + deleteButton.click(); + }); + }); + + test('Delete organization functionality should work properly for sample org', async () => { + mockURL = '123'; + setItem('SuperAdmin', true); + await act(async () => { + render( + + + + + + + + + , + ); + }); + await waitFor(() => { + expect(screen.getByTestId('openDeleteModalBtn')).toBeInTheDocument(); + }); + act(() => { + screen.getByTestId('openDeleteModalBtn').click(); + }); + await waitFor(() => { + expect(screen.getByTestId('orgDeleteModal')).toBeInTheDocument(); + }); + const deleteButton = await screen.findByTestId('deleteOrganizationBtn'); + act(() => { + deleteButton.click(); + }); + await wait(2000); + expect(mockNavgatePush).toHaveBeenCalledWith('/orglist'); + }); + + test('Error handling for IS_SAMPLE_ORGANIZATION_QUERY mock', async () => { + mockURL = '123'; + setItem('SuperAdmin', true); + jest.spyOn(toast, 'error'); + await act(async () => { + render( + + + + + + + + + , + ); + }); + await waitFor(() => { + expect(screen.getByTestId('openDeleteModalBtn')).toBeInTheDocument(); + }); + act(() => { + screen.getByTestId('openDeleteModalBtn').click(); + }); + await waitFor(() => { + expect(screen.getByTestId('orgDeleteModal')).toBeInTheDocument(); + }); + act(() => { + screen.getByTestId('deleteOrganizationBtn').click(); + }); + await waitFor(() => { + expect(toast.error).toHaveBeenCalledWith( + 'Failed to delete sample organization', + ); + }); + }); + + test('Error handling for DELETE_ORGANIZATION_MUTATION mock', async () => { + mockURL = '456'; + setItem('SuperAdmin', true); + jest.spyOn(toast, 'error'); + + await act(async () => { + render( + + + + + + + + + , + ); + }); + await waitFor(() => { + expect(screen.getByTestId('openDeleteModalBtn')).toBeInTheDocument(); + }); + act(() => { + screen.getByTestId('openDeleteModalBtn').click(); + }); + await waitFor(() => { + expect(screen.getByTestId('orgDeleteModal')).toBeInTheDocument(); + }); + act(() => { + screen.getByTestId('deleteOrganizationBtn').click(); + }); + await waitFor(() => { + expect(toast.error).toHaveBeenCalledWith('Failed to delete organization'); + }); + }); +}); diff --git a/src/components/DeleteOrg/DeleteOrg.tsx b/src/components/OrgSettings/General/DeleteOrg/DeleteOrg.tsx similarity index 76% rename from src/components/DeleteOrg/DeleteOrg.tsx rename to src/components/OrgSettings/General/DeleteOrg/DeleteOrg.tsx index ab2772785f..8edf11ca22 100644 --- a/src/components/DeleteOrg/DeleteOrg.tsx +++ b/src/components/OrgSettings/General/DeleteOrg/DeleteOrg.tsx @@ -13,34 +13,63 @@ import styles from './DeleteOrg.module.css'; import { useNavigate, useParams } from 'react-router-dom'; import useLocalStorage from 'utils/useLocalstorage'; +/** + * A component for deleting an organization. + * + * It displays a card with a delete button. When the delete button is clicked, + * a modal appears asking for confirmation. Depending on the type of organization + * (sample or regular), it performs the delete operation and shows appropriate + * success or error messages. + * + * @returns JSX.Element - The rendered component with delete functionality. + */ function deleteOrg(): JSX.Element { + // Translation hook for localization const { t } = useTranslation('translation', { keyPrefix: 'deleteOrg', }); const { t: tCommon } = useTranslation('common'); + + // Get the current organization ID from the URL const { orgId: currentUrl } = useParams(); + // Navigation hook for redirecting const navigate = useNavigate(); + // State to control the visibility of the delete confirmation modal const [showDeleteModal, setShowDeleteModal] = useState(false); + + // Hook for accessing local storage const { getItem } = useLocalStorage(); + // Check if the user has super admin privileges const canDelete = getItem('SuperAdmin'); + + /** + * Toggles the visibility of the delete confirmation modal. + */ const toggleDeleteModal = (): void => setShowDeleteModal(!showDeleteModal); + // GraphQL mutations for deleting organizations const [del] = useMutation(DELETE_ORGANIZATION_MUTATION); const [removeSampleOrganization] = useMutation( REMOVE_SAMPLE_ORGANIZATION_MUTATION, ); + // Query to check if the organization is a sample organization const { data } = useQuery(IS_SAMPLE_ORGANIZATION_QUERY, { variables: { isSampleOrganizationId: currentUrl, }, }); + /** + * Deletes the organization. It handles both sample and regular organizations. + * Displays success or error messages based on the operation result. + */ const deleteOrg = async (): Promise => { if (data && data.isSampleOrganization) { + // If it's a sample organization, use a specific mutation removeSampleOrganization() .then(() => { - toast.success(t('successfullyDeletedSampleOrganization')); + toast.success(t('successfullyDeletedSampleOrganization') as string); setTimeout(() => { navigate('/orglist'); }, 1000); @@ -49,6 +78,7 @@ function deleteOrg(): JSX.Element { toast.error(error.message); }); } else { + // For regular organizations, use a different mutation try { await del({ variables: { diff --git a/src/components/OrgSettings/General/GeneralSettings.tsx b/src/components/OrgSettings/General/GeneralSettings.tsx new file mode 100644 index 0000000000..4dbca1b6eb --- /dev/null +++ b/src/components/OrgSettings/General/GeneralSettings.tsx @@ -0,0 +1,73 @@ +import React, { type FC } from 'react'; +import { Card, Col, Form, Row } from 'react-bootstrap'; +import styles from 'screens/OrgSettings/OrgSettings.module.css'; +import OrgProfileFieldSettings from './OrgProfileFieldSettings/OrgProfileFieldSettings'; +import ChangeLanguageDropDown from 'components/ChangeLanguageDropdown/ChangeLanguageDropDown'; +import DeleteOrg from './DeleteOrg/DeleteOrg'; +import OrgUpdate from './OrgUpdate/OrgUpdate'; +import { useTranslation } from 'react-i18next'; + +/** + * Props for the `GeneralSettings` component. + */ +interface InterfaceGeneralSettingsProps { + orgId: string; +} + +/** + * A component for displaying general settings for an organization. + * + * @param props - The properties passed to the component. + * @returns The `GeneralSettings` component. + */ +const GeneralSettings: FC = ({ orgId }) => { + const { t } = useTranslation('translation', { + keyPrefix: 'orgSettings', + }); + + return ( + + + +
    +
    {t('updateOrganization')}
    +
    + + {/* Render organization update component */} + + +
    + + + + +
    +
    {t('otherSettings')}
    +
    + +
    + + {t('changeLanguage')} + + {/* Render language change dropdown component */} + +
    +
    +
    + + + +
    +
    {t('manageCustomFields')}
    +
    + + {/* Render organization profile field settings component */} + + +
    + +
    + ); +}; + +export default GeneralSettings; diff --git a/src/components/OrgProfileFieldSettings/OrgProfileFieldSettings.module.css b/src/components/OrgSettings/General/OrgProfileFieldSettings/OrgProfileFieldSettings.module.css similarity index 100% rename from src/components/OrgProfileFieldSettings/OrgProfileFieldSettings.module.css rename to src/components/OrgSettings/General/OrgProfileFieldSettings/OrgProfileFieldSettings.module.css diff --git a/src/components/OrgProfileFieldSettings/OrgProfileFieldSettings.test.tsx b/src/components/OrgSettings/General/OrgProfileFieldSettings/OrgProfileFieldSettings.test.tsx similarity index 98% rename from src/components/OrgProfileFieldSettings/OrgProfileFieldSettings.test.tsx rename to src/components/OrgSettings/General/OrgProfileFieldSettings/OrgProfileFieldSettings.test.tsx index 2630c6c4ee..8db8773381 100644 --- a/src/components/OrgProfileFieldSettings/OrgProfileFieldSettings.test.tsx +++ b/src/components/OrgSettings/General/OrgProfileFieldSettings/OrgProfileFieldSettings.test.tsx @@ -1,5 +1,5 @@ -import React from 'react'; -import { act, render, screen } from '@testing-library/react'; +import React, { act } from 'react'; +import { render, screen } from '@testing-library/react'; import { MockedProvider } from '@apollo/react-testing'; import userEvent from '@testing-library/user-event'; import { I18nextProvider } from 'react-i18next'; diff --git a/src/components/OrgProfileFieldSettings/OrgProfileFieldSettings.tsx b/src/components/OrgSettings/General/OrgProfileFieldSettings/OrgProfileFieldSettings.tsx similarity index 82% rename from src/components/OrgProfileFieldSettings/OrgProfileFieldSettings.tsx rename to src/components/OrgSettings/General/OrgProfileFieldSettings/OrgProfileFieldSettings.tsx index ba2d3a9c02..dcb6992e21 100644 --- a/src/components/OrgProfileFieldSettings/OrgProfileFieldSettings.tsx +++ b/src/components/OrgSettings/General/OrgProfileFieldSettings/OrgProfileFieldSettings.tsx @@ -13,28 +13,39 @@ import { useTranslation } from 'react-i18next'; import { toast } from 'react-toastify'; import EditOrgCustomFieldDropDown from 'components/EditCustomFieldDropDown/EditCustomFieldDropDown'; import { useParams } from 'react-router-dom'; +import type { InterfaceCustomFieldData } from 'utils/interfaces'; -export interface InterfaceCustomFieldData { - type: string; - name: string; -} - +/** + * Component for managing organization profile field settings + * + * This component allows adding and removing custom fields for an organization. + * It displays existing custom fields and provides a form to add new fields. + * + * @returns JSX.Element representing the organization profile field settings + */ const OrgProfileFieldSettings = (): JSX.Element => { const { t } = useTranslation('translation', { keyPrefix: 'orgProfileField', }); const { t: tCommon } = useTranslation('common'); + // State to hold the custom field data const [customFieldData, setCustomFieldData] = useState({ type: '', name: '', }); + + // Get the current organization ID from the URL parameters const { orgId: currentOrgId } = useParams(); + // Mutation to add a custom field const [addCustomField] = useMutation(ADD_CUSTOM_FIELD); + + // Mutation to remove a custom field const [removeCustomField] = useMutation(REMOVE_CUSTOM_FIELD); + // Query to fetch custom fields for the organization const { loading, error, data, refetch } = useQuery( ORGANIZATION_CUSTOM_FIELDS, { @@ -44,6 +55,7 @@ const OrgProfileFieldSettings = (): JSX.Element => { }, ); + // Function to handle saving a new custom field const handleSave = async (): Promise => { try { await addCustomField({ @@ -52,7 +64,7 @@ const OrgProfileFieldSettings = (): JSX.Element => { ...customFieldData, }, }); - toast.success(t('fieldSuccessMessage')); + toast.success(t('fieldSuccessMessage') as string); setCustomFieldData({ type: '', name: '' }); refetch(); } catch (error) { @@ -60,6 +72,7 @@ const OrgProfileFieldSettings = (): JSX.Element => { } }; + // Function to handle removing a custom field const handleRemove = async (customFieldId: string): Promise => { try { await removeCustomField({ @@ -69,18 +82,20 @@ const OrgProfileFieldSettings = (): JSX.Element => { }, }); - toast.success(t('fieldRemovalSuccess')); + toast.success(t('fieldRemovalSuccess') as string); refetch(); } catch (error) { toast.error((error as Error).message); } }; + // Render loading or error messages if needed if (loading) return

    {tCommon('loading')}

    ; if (error) return

    {error.message}

    ; return (
    + {/* Display existing custom fields or a message if there are none */} {data.customFieldsByOrganization.length === 0 ? (

    {t('noCustomField')}

    ) : ( @@ -99,6 +114,7 @@ const OrgProfileFieldSettings = (): JSX.Element => { {field.name} {field.type} + {/* Button to remove a custom field */}
    + )) + )} +
    + +
    + {t('allTags')} +
    + +
    + +
    +
    + } + scrollableTarget="scrollableDiv" + > + {userTagsList?.map((tag) => ( +
    + +
    + ))} +
    +
    + + )} + + + + + + + + + + ); +}; + +export default TagActions; diff --git a/src/components/TagActions/TagActionsMocks.ts b/src/components/TagActions/TagActionsMocks.ts new file mode 100644 index 0000000000..4e3a08f184 --- /dev/null +++ b/src/components/TagActions/TagActionsMocks.ts @@ -0,0 +1,533 @@ +import { + ASSIGN_TO_TAGS, + REMOVE_FROM_TAGS, +} from 'GraphQl/Mutations/TagMutations'; +import { ORGANIZATION_USER_TAGS_LIST } from 'GraphQl/Queries/OrganizationQueries'; +import { USER_TAG_SUB_TAGS } from 'GraphQl/Queries/userTagQueries'; +import { TAGS_QUERY_LIMIT } from 'utils/organizationTagsUtils'; + +export const MOCKS = [ + { + request: { + query: ORGANIZATION_USER_TAGS_LIST, + variables: { + id: '123', + first: TAGS_QUERY_LIMIT, + }, + }, + result: { + data: { + organizations: [ + { + userTags: { + edges: [ + { + node: { + _id: '1', + name: 'userTag 1', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 11, + }, + }, + cursor: '1', + }, + { + node: { + _id: '2', + name: 'userTag 2', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 0, + }, + }, + cursor: '2', + }, + { + node: { + _id: '3', + name: 'userTag 3', + usersAssignedTo: { + totalCount: 0, + }, + childTags: { + totalCount: 5, + }, + }, + cursor: '3', + }, + { + node: { + _id: '4', + name: 'userTag 4', + usersAssignedTo: { + totalCount: 0, + }, + childTags: { + totalCount: 0, + }, + }, + cursor: '4', + }, + { + node: { + _id: '5', + name: 'userTag 5', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 5, + }, + }, + cursor: '5', + }, + { + node: { + _id: '6', + name: 'userTag 6', + usersAssignedTo: { + totalCount: 6, + }, + childTags: { + totalCount: 6, + }, + }, + cursor: '6', + }, + { + node: { + _id: '7', + name: 'userTag 7', + usersAssignedTo: { + totalCount: 7, + }, + childTags: { + totalCount: 7, + }, + }, + cursor: '7', + }, + { + node: { + _id: '8', + name: 'userTag 8', + usersAssignedTo: { + totalCount: 8, + }, + childTags: { + totalCount: 8, + }, + }, + cursor: '8', + }, + { + node: { + _id: '9', + name: 'userTag 9', + usersAssignedTo: { + totalCount: 9, + }, + childTags: { + totalCount: 9, + }, + }, + cursor: '9', + }, + { + node: { + _id: '10', + name: 'userTag 10', + usersAssignedTo: { + totalCount: 10, + }, + childTags: { + totalCount: 10, + }, + }, + cursor: '10', + }, + ], + pageInfo: { + startCursor: '1', + endCursor: '10', + hasNextPage: true, + hasPreviousPage: false, + }, + totalCount: 12, + }, + }, + ], + }, + }, + }, + { + request: { + query: ORGANIZATION_USER_TAGS_LIST, + variables: { + id: '123', + first: TAGS_QUERY_LIMIT, + after: '10', + }, + }, + result: { + data: { + organizations: [ + { + userTags: { + edges: [ + { + node: { + _id: '11', + name: 'userTag 11', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 5, + }, + }, + cursor: '11', + }, + { + node: { + _id: '12', + name: 'userTag 12', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 0, + }, + }, + cursor: '12', + }, + ], + pageInfo: { + startCursor: '11', + endCursor: '12', + hasNextPage: false, + hasPreviousPage: true, + }, + totalCount: 12, + }, + }, + ], + }, + }, + }, + { + request: { + query: USER_TAG_SUB_TAGS, + variables: { + id: '1', + first: TAGS_QUERY_LIMIT, + }, + }, + result: { + data: { + getUserTag: { + name: 'userTag 1', + childTags: { + edges: [ + { + node: { + _id: 'subTag1', + name: 'subTag 1', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 5, + }, + }, + cursor: 'subTag1', + }, + { + node: { + _id: 'subTag2', + name: 'subTag 2', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 0, + }, + }, + cursor: 'subTag2', + }, + { + node: { + _id: 'subTag3', + name: 'subTag 3', + usersAssignedTo: { + totalCount: 0, + }, + childTags: { + totalCount: 5, + }, + }, + cursor: 'subTag3', + }, + { + node: { + _id: 'subTag4', + name: 'subTag 4', + usersAssignedTo: { + totalCount: 0, + }, + childTags: { + totalCount: 0, + }, + }, + cursor: 'subTag4', + }, + { + node: { + _id: 'subTag5', + name: 'subTag 5', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 5, + }, + }, + cursor: 'subTag5', + }, + { + node: { + _id: 'subTag6', + name: 'subTag 6', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 5, + }, + }, + cursor: 'subTag6', + }, + { + node: { + _id: 'subTag7', + name: 'subTag 7', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 5, + }, + }, + cursor: 'subTag7', + }, + { + node: { + _id: 'subTag8', + name: 'subTag 8', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 5, + }, + }, + cursor: 'subTag8', + }, + { + node: { + _id: 'subTag9', + name: 'subTag 9', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 5, + }, + }, + cursor: 'subTag9', + }, + { + node: { + _id: 'subTag10', + name: 'subTag 10', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 5, + }, + }, + cursor: 'subTag10', + }, + ], + pageInfo: { + startCursor: 'subTag1', + endCursor: 'subTag10', + hasNextPage: true, + hasPreviousPage: false, + }, + totalCount: 11, + }, + }, + }, + }, + }, + { + request: { + query: USER_TAG_SUB_TAGS, + variables: { + id: '1', + after: 'subTag10', + first: TAGS_QUERY_LIMIT, + }, + }, + result: { + data: { + getUserTag: { + name: 'userTag 1', + childTags: { + edges: [ + { + node: { + _id: 'subTag11', + name: 'subTag 11', + usersAssignedTo: { + totalCount: 0, + }, + childTags: { + totalCount: 0, + }, + }, + cursor: 'subTag11', + }, + ], + pageInfo: { + startCursor: 'subTag11', + endCursor: 'subTag11', + hasNextPage: false, + hasPreviousPage: true, + }, + totalCount: 11, + }, + }, + }, + }, + }, + { + request: { + query: ASSIGN_TO_TAGS, + variables: { + currentTagId: '1', + selectedTagIds: ['2', '3'], + }, + }, + result: { + data: { + assignToUserTags: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: REMOVE_FROM_TAGS, + variables: { + currentTagId: '1', + selectedTagIds: ['2'], + }, + }, + result: { + data: { + removeFromUserTags: { + _id: '1', + }, + }, + }, + }, +]; + +export const MOCKS_ERROR_ORGANIZATION_TAGS_QUERY = [ + { + request: { + query: ORGANIZATION_USER_TAGS_LIST, + variables: { + id: '123', + first: TAGS_QUERY_LIMIT, + }, + }, + error: new Error('Mock Graphql Error for organization root tags query'), + }, +]; + +export const MOCKS_ERROR_SUBTAGS_QUERY = [ + { + request: { + query: ORGANIZATION_USER_TAGS_LIST, + variables: { + id: '123', + first: TAGS_QUERY_LIMIT, + }, + }, + result: { + data: { + organizations: [ + { + userTags: { + edges: [ + { + node: { + _id: '1', + name: 'userTag 1', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 11, + }, + }, + cursor: '1', + }, + { + node: { + _id: '2', + name: 'userTag 2', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 0, + }, + }, + cursor: '2', + }, + ], + pageInfo: { + startCursor: '1', + endCursor: '2', + hasNextPage: false, + hasPreviousPage: false, + }, + totalCount: 2, + }, + }, + ], + }, + }, + }, + { + request: { + query: USER_TAG_SUB_TAGS, + variables: { + id: '1', + first: TAGS_QUERY_LIMIT, + }, + }, + error: new Error('Mock Graphql Error for subTags query'), + }, +]; diff --git a/src/components/TagActions/TagNode.tsx b/src/components/TagActions/TagNode.tsx new file mode 100644 index 0000000000..db08c3b451 --- /dev/null +++ b/src/components/TagActions/TagNode.tsx @@ -0,0 +1,219 @@ +import type { ApolloError } from '@apollo/client'; +import { useQuery } from '@apollo/client'; +import { USER_TAG_SUB_TAGS } from 'GraphQl/Queries/userTagQueries'; +import React, { useState } from 'react'; +import type { + InterfaceQueryUserTagChildTags, + InterfaceTagData, +} from 'utils/interfaces'; +import { TAGS_QUERY_LIMIT } from 'utils/organizationTagsUtils'; +import styles from './TagActions.module.css'; +import InfiniteScroll from 'react-infinite-scroll-component'; +import { WarningAmberRounded } from '@mui/icons-material'; + +/** + * Props for the `TagNode` component. + */ +interface InterfaceTagNodeProps { + tag: InterfaceTagData; + checkedTags: Set; + toggleTagSelection: (tag: InterfaceTagData, isSelected: boolean) => void; + t: (key: string) => string; +} + +/** + * Renders the Tags which can be expanded to list subtags. + */ +const TagNode: React.FC = ({ + tag, + checkedTags, + toggleTagSelection, + t, +}) => { + const [expanded, setExpanded] = useState(false); + + const { + data: subTagsData, + loading: subTagsLoading, + error: subTagsError, + fetchMore: fetchMoreSubTags, + }: { + data?: { + getUserTag: InterfaceQueryUserTagChildTags; + }; + loading: boolean; + error?: ApolloError; + refetch: () => void; + fetchMore: (options: { + variables: { + first: number; + after?: string; + }; + updateQuery: ( + previousResult: { getUserTag: InterfaceQueryUserTagChildTags }, + options: { + fetchMoreResult?: { getUserTag: InterfaceQueryUserTagChildTags }; + }, + ) => { getUserTag: InterfaceQueryUserTagChildTags }; + }) => void; + } = useQuery(USER_TAG_SUB_TAGS, { + variables: { + id: tag._id, + first: TAGS_QUERY_LIMIT, + }, + skip: !expanded, + }); + + if (subTagsError) { + return ( +
    +
    + +
    + {t('errorOccurredWhileLoadingSubTags')} +
    +
    +
    + ); + } + + const subTagsList = subTagsData?.getUserTag.childTags.edges.map( + (edge) => edge.node, + ); + + const handleTagClick = (): void => { + setExpanded(!expanded); + }; + + const handleCheckboxChange = ( + e: React.ChangeEvent, + ): void => { + toggleTagSelection(tag, e.target.checked); + }; + + const loadMoreSubTags = (): void => { + fetchMoreSubTags({ + variables: { + first: TAGS_QUERY_LIMIT, + after: subTagsData?.getUserTag.childTags.pageInfo.endCursor, + }, + updateQuery: ( + prevResult: { getUserTag: InterfaceQueryUserTagChildTags }, + { + fetchMoreResult, + }: { + fetchMoreResult?: { getUserTag: InterfaceQueryUserTagChildTags }; + }, + ) => { + if (!fetchMoreResult) return prevResult; + + return { + getUserTag: { + ...fetchMoreResult.getUserTag, + childTags: { + ...fetchMoreResult.getUserTag.childTags, + edges: [ + ...prevResult.getUserTag.childTags.edges, + ...fetchMoreResult.getUserTag.childTags.edges, + ], + }, + }, + }; + }, + }); + }; + + return ( +
    +
    + {tag.childTags.totalCount ? ( + <> + + {expanded ? '▼' : '▶'} + + + {' '} + + ) : ( + <> + + + {' '} + + )} + + {tag.name} +
    + + {expanded && subTagsLoading && ( +
    +
    +
    +
    +
    + )} + {expanded && subTagsList?.length && ( +
    +
    + +
    +
    + } + scrollableTarget={`subTagsScrollableDiv${tag._id}`} + > + {subTagsList.map((tag: InterfaceTagData) => ( +
    + +
    + ))} +
    +
    +
    + )} +
    + ); +}; + +export default TagNode; diff --git a/src/components/UpdateSession/UpdateSession.css b/src/components/UpdateSession/UpdateSession.css new file mode 100644 index 0000000000..073bbf973d --- /dev/null +++ b/src/components/UpdateSession/UpdateSession.css @@ -0,0 +1,96 @@ +/* Card styles */ +.update-timeout-card { + width: 700px; + background: #ffffff; + border: none; + border-radius: 16px; + filter: drop-shadow(0px 4px 15.3px rgba(0, 0, 0, 0.08)); + padding: 20px; +} + +.update-timeout-card-header { + background: none; + padding: 16px; + border-bottom: none; +} + +.update-timeout-card-title { + font-family: 'Lato', sans-serif; + font-weight: 600; + font-size: 24px; + color: #000000; +} + +.update-timeout-card-body { + padding: 20px; +} + +.update-timeout-current { + font-family: 'Lato', sans-serif; + font-weight: 400; + font-size: 16px; + color: #000000; + margin-bottom: 20px; /* Increased margin to create more space */ +} + +.update-timeout-label { + font-family: 'Lato', sans-serif; + font-weight: 400; + font-size: 16px; + color: #000000; + margin-bottom: 10px; /* Keep the same margin to maintain spacing with the slider */ +} + +.update-timeout-labels-container { + display: flex; + flex-direction: column; + align-items: start; +} + +.update-timeout-value { + color: #14ae5c; + font-weight: bold; +} + +.update-timeout-slider-labels { + display: flex; + justify-content: space-between; + font-size: 0.9rem; + color: #757575; +} + +.update-timeout-button-container { + display: flex; + justify-content: right; + margin-top: 20px; +} + +.update-timeout-button { + width: 112px; + height: 36px; + background: #31bb6b; + border-radius: 6px; + font-family: 'Lato', sans-serif; + font-weight: 500; + font-size: 16px; + color: #ffffff; + display: flex; + align-items: center; + justify-content: center; + border: none; + box-shadow: none; +} + +.update-timeout-button:hover { + background-color: #28a745; + border-color: #28a745; + box-shadow: none; +} + +.update-timeout-button:active { + transform: scale(0.98); +} + +.update-timeout-slider-container { + position: relative; +} diff --git a/src/components/UpdateSession/UpdateSession.test.tsx b/src/components/UpdateSession/UpdateSession.test.tsx new file mode 100644 index 0000000000..ce0a868820 --- /dev/null +++ b/src/components/UpdateSession/UpdateSession.test.tsx @@ -0,0 +1,346 @@ +import React from 'react'; +import { MockedProvider } from '@apollo/client/testing'; +import { + render, + screen, + act, + within, + fireEvent, + waitFor, +} from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import 'jest-localstorage-mock'; +import 'jest-location-mock'; +import { I18nextProvider } from 'react-i18next'; +import { BrowserRouter } from 'react-router-dom'; +import { toast } from 'react-toastify'; +import UpdateTimeout from './UpdateSession'; +import i18n from 'utils/i18nForTest'; +import { GET_COMMUNITY_SESSION_TIMEOUT_DATA } from 'GraphQl/Queries/Queries'; +import { UPDATE_SESSION_TIMEOUT } from 'GraphQl/Mutations/mutations'; +import { errorHandler } from 'utils/errorHandler'; + +const MOCKS = [ + { + request: { + query: GET_COMMUNITY_SESSION_TIMEOUT_DATA, + }, + result: { + data: { + getCommunityData: { + timeout: 30, + }, + }, + }, + }, + { + request: { + query: GET_COMMUNITY_SESSION_TIMEOUT_DATA, + }, + result: { + data: { + getCommunityData: null, + }, + }, + }, + { + request: { + query: UPDATE_SESSION_TIMEOUT, + variables: { + timeout: 30, + }, + }, + result: { + data: { + updateSessionTimeout: true, + }, + }, + }, +]; + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }, +})); + +jest.mock('utils/errorHandler', () => ({ + errorHandler: jest.fn(), +})); + +describe('Testing UpdateTimeout Component', () => { + let consoleWarnSpy: jest.SpyInstance; + + beforeEach(() => { + consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation(); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test('Should handle minimum slider value correctly', async () => { + const mockOnValueChange = jest.fn(); + + render( + + + , + ); + + const slider = await screen.findByTestId('slider-thumb'); + + // Simulate dragging to minimum value + userEvent.click(slider, { + // Simulate clicking on the slider to focus + clientX: -999, // Adjust the clientX to simulate different slider positions + }); + + expect(mockOnValueChange).toHaveBeenCalledWith(15); // Adjust based on slider min value + }); + + test('Should handle maximum slider value correctly', async () => { + const mockOnValueChange = jest.fn(); + + render( + + + , + ); + + const slider = await screen.findByTestId('slider-thumb'); + + // Simulate dragging to maximum value + userEvent.click(slider, { + // Simulate clicking on the slider to focus + clientX: 999, // Adjust the clientX to simulate different slider positions + }); + + expect(mockOnValueChange).toHaveBeenCalledWith(60); // Adjust based on slider max value + }); + + test('Should not update value if an invalid value is passed', async () => { + const mockOnValueChange = jest.fn(); + + render( + + + , + ); + + const slider = await screen.findByTestId('slider-thumb'); + + // Simulate invalid value handling + userEvent.click(slider, { + // Simulate clicking on the slider to focus + clientX: 0, // Adjust the clientX to simulate different slider positions + }); + + // Ensure onValueChange is not called with invalid values + expect(mockOnValueChange).not.toHaveBeenCalled(); + }); + + test('Should update slider value on user interaction', async () => { + const mockOnValueChange = jest.fn(); + + render( + + + , + ); + + // Wait for the slider to be present + const slider = await screen.findByTestId('slider-thumb'); + + // Simulate slider interaction + userEvent.type(slider, '45'); // Simulate typing value + + // Assert that the callback was called with the expected value + expect(mockOnValueChange).toHaveBeenCalledWith(expect.any(Number)); // Adjust as needed + }); + + test('Components should render properly', async () => { + render( + + + + + + + , + ); + + await wait(); + + // Use getAllByText to get all elements with "Update Timeout" text + const updateTimeoutElements = screen.getAllByText(/Update Timeout/i); + expect(updateTimeoutElements).toHaveLength(1); // Check if there are exactly 2 elements with this text + + expect(screen.getByText(/Current Timeout/i)).toBeInTheDocument(); + expect(screen.getByText(/15 min/i)).toBeInTheDocument(); + + // Locate the parent element first + const sliderLabelsContainer = screen.getByTestId('slider-labels'); + + // Use within to query inside the parent element + const sliderLabels = within(sliderLabelsContainer); + + // Check for the specific text within the parent element + expect(sliderLabels.getByText('30 min')).toBeInTheDocument(); + + expect(screen.getByText(/45 min/i)).toBeInTheDocument(); + expect(screen.getByText(/60 min/i)).toBeInTheDocument(); + expect(screen.getByRole('button', { name: /Update/i })).toBeInTheDocument(); + }); + + test('Should update session timeout', async () => { + render( + + + + + + + , + ); + + await wait(); + + const submitButton = screen.getByTestId('update-button'); + userEvent.click(submitButton); + + // Wait for the toast success call + + await wait(); + + expect(toast.success).toHaveBeenCalledWith( + expect.stringContaining('Successfully updated the Profile Details.'), + ); + }); + + test('Should handle query errors', async () => { + const errorMocks = [ + { + request: { + query: GET_COMMUNITY_SESSION_TIMEOUT_DATA, + }, + error: new Error('An error occurred'), + }, + ]; + + render( + + + + + + + , + ); + + await wait(); + + expect(errorHandler).toHaveBeenCalled(); + }); + + test('Should handle update errors', async () => { + const errorMocks = [ + { + request: { + query: GET_COMMUNITY_SESSION_TIMEOUT_DATA, + }, + result: { + data: { + getCommunityData: { + timeout: 30, + }, + }, + }, + }, + { + request: { + query: GET_COMMUNITY_SESSION_TIMEOUT_DATA, + }, + result: { + data: { + getCommunityData: null, + }, + }, + }, + { + request: { + query: UPDATE_SESSION_TIMEOUT, + variables: { timeout: 30 }, + }, + error: new Error('An error occurred'), + }, + ]; + + render( + + + + + + + , + ); + + await wait(); + + const submitButton = screen.getByTestId('update-button'); + userEvent.click(submitButton); + + await wait(); + + expect(errorHandler).toHaveBeenCalled(); + }); + + test('Should handle null community object gracefully', async () => { + render( + + + + + + + , + ); + + await wait(); + + // Assertions to verify the component handles null community object correctly + // Use getAllByText to get all elements with "Update Timeout" text + const updateTimeoutElements = screen.getAllByText(/Update Timeout/i); + expect(updateTimeoutElements).toHaveLength(1); // Check if there are exactly 2 elements with this text + + expect(screen.getByText(/Current Timeout/i)).toBeInTheDocument(); + + // Locate the parent element first + const sliderLabelsContainer = screen.getByTestId('slider-labels'); + + // Use within to query inside the parent element + const sliderLabels = within(sliderLabelsContainer); + + // Check for the specific text within the parent element + expect(sliderLabels.getByText('15 min')).toBeInTheDocument(); + + expect(screen.getByText(/30 min/i)).toBeInTheDocument(); + expect(screen.getByText(/45 min/i)).toBeInTheDocument(); + expect(screen.getByText(/60 min/i)).toBeInTheDocument(); + expect(screen.getByRole('button', { name: /Update/i })).toBeInTheDocument(); + + // Check if the component displays a default value or handles the null state appropriately + expect(screen.getByText(/No timeout set/i)).toBeInTheDocument(); + }); +}); diff --git a/src/components/UpdateSession/UpdateSession.tsx b/src/components/UpdateSession/UpdateSession.tsx new file mode 100644 index 0000000000..f49970ebaa --- /dev/null +++ b/src/components/UpdateSession/UpdateSession.tsx @@ -0,0 +1,202 @@ +import React, { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Card, Button, Form } from 'react-bootstrap'; +import Box from '@mui/material/Box'; +import Slider from '@mui/material/Slider'; +import { useMutation, useQuery } from '@apollo/client'; +import { GET_COMMUNITY_SESSION_TIMEOUT_DATA } from 'GraphQl/Queries/Queries'; +import { toast } from 'react-toastify'; +import { errorHandler } from 'utils/errorHandler'; +import { UPDATE_SESSION_TIMEOUT } from 'GraphQl/Mutations/mutations'; +import './UpdateSession.css'; +import Loader from 'components/Loader/Loader'; + +/** + * Component for updating the session timeout for a community. + * + * This component fetches the current session timeout value from the server + * and allows the user to update it using a slider. + * + * The component also handles form submission, making a mutation request to update the session timeout. + * + * @returns JSX.Element - The rendered component. + */ + +interface TestInterfaceUpdateTimeoutProps { + onValueChange?: (value: number) => void; +} + +const UpdateTimeout: React.FC = ({ + onValueChange, +}): JSX.Element => { + const { t } = useTranslation('translation', { + keyPrefix: 'communityProfile', + }); + + const [timeout, setTimeout] = useState(30); + const [communityTimeout, setCommunityTimeout] = useState( + 30, + ); // Timeout from database for the community + + const { + data, + loading, + error: queryError, + } = useQuery(GET_COMMUNITY_SESSION_TIMEOUT_DATA); + const [uploadSessionTimeout] = useMutation(UPDATE_SESSION_TIMEOUT); + + type TimeoutDataType = { + timeout: number; + }; + + /** + * Effect that fetches the current session timeout from the server and sets the initial state. + * If there is an error in fetching the data, it is handled using the error handler. + */ + React.useEffect(() => { + if (queryError) { + errorHandler(t, queryError as Error); + } + + const SessionTimeoutData: TimeoutDataType | undefined = + data?.getCommunityData; + + if (SessionTimeoutData && SessionTimeoutData.timeout !== null) { + setCommunityTimeout(SessionTimeoutData.timeout); + setTimeout(SessionTimeoutData.timeout); + } else { + setCommunityTimeout(undefined); // Handle null or undefined data + } + }, [data, queryError]); + + /** + * Handles changes to the slider value and updates the timeout state. + * + * @param e - The event triggered by slider movement. + */ + const handleOnChange = ( + e: Event | React.ChangeEvent, + ): void => { + if ('target' in e && e.target) { + const target = e.target as HTMLInputElement; + // Ensure the value is a number and not NaN + const value = parseInt(target.value, 10); + if (!Number.isNaN(value)) { + setTimeout(value); + if (onValueChange) { + onValueChange(value); + } + } else { + console.warn('Invalid timeout value:', target.value); + } + } + }; + + /** + * Handles form submission to update the session timeout. + * It makes a mutation request to update the timeout value on the server. + * If the update is successful, a success toast is shown, and the state is updated. + * + * @param e - The event triggered by form submission. + */ + const handleOnSubmit = async ( + e: React.FormEvent, + ): Promise => { + e.preventDefault(); + try { + await uploadSessionTimeout({ + variables: { + timeout: timeout, + }, + }); + + toast.success(t('profileChangedMsg')); + setCommunityTimeout(timeout); + } catch (error: unknown) { + /* istanbul ignore next */ + errorHandler(t, error as Error); + } + }; + + // Show a loader while the data is being fetched + if (loading) { + return ; + } + + return ( + <> + + +
    Login Session Timeout
    +
    + +
    +
    + + Current Timeout: + + {communityTimeout !== undefined + ? ` ${communityTimeout} minutes` + : ' No timeout set'} + + + + + Update Timeout + +
    + + + + + +
    + 15 min + 30 min + 45 min + 60 min +
    +
    + +
    +
    +
    +
    + + ); +}; + +export default UpdateTimeout; diff --git a/src/components/UserListCard/UserListCard.test.tsx b/src/components/UserListCard/UserListCard.test.tsx index 9f59bb92ce..e2ad552507 100644 --- a/src/components/UserListCard/UserListCard.test.tsx +++ b/src/components/UserListCard/UserListCard.test.tsx @@ -1,5 +1,5 @@ -import React from 'react'; -import { act, render, screen } from '@testing-library/react'; +import React, { act } from 'react'; +import { render, screen } from '@testing-library/react'; import { MockedProvider } from '@apollo/react-testing'; import userEvent from '@testing-library/user-event'; import { I18nextProvider } from 'react-i18next'; @@ -14,7 +14,7 @@ const MOCKS = [ { request: { query: ADD_ADMIN_MUTATION, - variable: { userid: '784', orgid: '554' }, + variables: { userid: '784', orgid: '554' }, }, result: { data: { @@ -28,6 +28,7 @@ const MOCKS = [ }, ]; const link = new StaticMockLink(MOCKS, true); + async function wait(ms = 100): Promise { await act(() => { return new Promise((resolve) => { @@ -41,7 +42,6 @@ describe('Testing User List Card', () => { test('Should render props and text elements test for the page component', async () => { const props = { - key: 123, id: '456', }; @@ -49,7 +49,7 @@ describe('Testing User List Card', () => { - + , @@ -62,7 +62,6 @@ describe('Testing User List Card', () => { test('Should render text elements when props value is not passed', async () => { const props = { - key: 123, id: '456', }; @@ -70,7 +69,7 @@ describe('Testing User List Card', () => { - + , diff --git a/src/components/UserListCard/UserListCard.tsx b/src/components/UserListCard/UserListCard.tsx index 5954e22e6c..76ad110ea1 100644 --- a/src/components/UserListCard/UserListCard.tsx +++ b/src/components/UserListCard/UserListCard.tsx @@ -14,6 +14,16 @@ interface InterfaceUserListCardProps { id: string; } +/** + * The UserListCard component allows for adding a user as an admin in a specific organization. + * It uses a button to trigger a mutation for updating the user's role. + * + * @param props - The properties for the UserListCard component. + * @param key - The unique key for the component (although not used here). + * @param id - The ID of the user to be promoted to admin. + * + * @returns The JSX element representing the user list card. + */ function userListCard(props: InterfaceUserListCardProps): JSX.Element { const { orgId: currentUrl } = useParams(); const [adda] = useMutation(ADD_ADMIN_MUTATION); @@ -22,6 +32,10 @@ function userListCard(props: InterfaceUserListCardProps): JSX.Element { keyPrefix: 'userListCard', }); + /** + * Handles adding a user as an admin. + * It performs a mutation and handles success or failure accordingly. + */ const addAdmin = async (): Promise => { try { const { data } = await adda({ @@ -33,12 +47,12 @@ function userListCard(props: InterfaceUserListCardProps): JSX.Element { /* istanbul ignore next */ if (data) { - toast.success(t('addedAsAdmin')); + toast.success(t('addedAsAdmin') as string); setTimeout(() => { window.location.reload(); }, 2000); } - } catch (error: any) { + } catch (error: unknown) { /* istanbul ignore next */ errorHandler(t, error); } diff --git a/src/components/UserPasswordUpdate/UserPasswordUpdate.test.tsx b/src/components/UserPasswordUpdate/UserPasswordUpdate.test.tsx index 2aa5756717..65f5e40f76 100644 --- a/src/components/UserPasswordUpdate/UserPasswordUpdate.test.tsx +++ b/src/components/UserPasswordUpdate/UserPasswordUpdate.test.tsx @@ -1,5 +1,5 @@ -import React from 'react'; -import { act, render, screen } from '@testing-library/react'; +import React, { act } from 'react'; +import { render, screen } from '@testing-library/react'; import { MockedProvider } from '@apollo/react-testing'; import userEvent from '@testing-library/user-event'; import { I18nextProvider } from 'react-i18next'; @@ -20,7 +20,7 @@ const MOCKS = [ { request: { query: UPDATE_USER_PASSWORD_MUTATION, - variable: { + variables: { previousPassword: 'anshgoyal', newPassword: 'anshgoyalansh', confirmNewPassword: 'anshgoyalansh', @@ -49,15 +49,10 @@ async function wait(ms = 5): Promise { } describe('Testing User Password Update', () => { - const props = { - key: '123', - id: '1', - }; - const formData = { previousPassword: 'Palisadoes', newPassword: 'ThePalisadoesFoundation', - wrongPassword: 'This is wrong passoword', + wrongPassword: 'This is wrong password', confirmNewPassword: 'ThePalisadoesFoundation', }; @@ -67,7 +62,7 @@ describe('Testing User Password Update', () => { render( - + , ); @@ -102,7 +97,7 @@ describe('Testing User Password Update', () => { render( - + , ); @@ -110,16 +105,14 @@ describe('Testing User Password Update', () => { userEvent.click(screen.getByText(/Save Changes/i)); await wait(); - expect(mockToast.error).toHaveBeenCalledWith( - 'The password field cannot be empty.', - ); + expect(mockToast.error).toHaveBeenCalledWith(`Password can't be empty`); }); test('displays an error when new and confirm password field does not match', async () => { render( - + , ); diff --git a/src/components/UserPasswordUpdate/UserPasswordUpdate.tsx b/src/components/UserPasswordUpdate/UserPasswordUpdate.tsx index 78fea1df53..1ea75811c1 100644 --- a/src/components/UserPasswordUpdate/UserPasswordUpdate.tsx +++ b/src/components/UserPasswordUpdate/UserPasswordUpdate.tsx @@ -11,6 +11,15 @@ interface InterfaceUserPasswordUpdateProps { id: string; } +/** + * UserUpdate component allows users to update their passwords. + * It handles form submission and communicates with the backend to update the user's password. + * + * @param props - The properties for the UserUpdate component. + * @param id - The ID of the user whose password is being updated. + * + * @returns The JSX element for updating user password. + */ const UserUpdate: React.FC< InterfaceUserPasswordUpdateProps > = (): JSX.Element => { @@ -26,18 +35,22 @@ const UserUpdate: React.FC< const [login] = useMutation(UPDATE_USER_PASSWORD_MUTATION); + /** + * Handles the password update process. + * It validates the form inputs and performs the mutation to update the password. + */ const loginLink = async (): Promise => { if ( !formState.previousPassword || !formState.newPassword || !formState.confirmNewPassword ) { - toast.error('The password field cannot be empty.'); + toast.error(t('passCantBeEmpty') as string); return; } if (formState.newPassword !== formState.confirmNewPassword) { - toast.error('New and Confirm password do not match.'); + toast.error(t('passNoMatch') as string); return; } @@ -51,7 +64,9 @@ const UserUpdate: React.FC< }); /* istanbul ignore next */ if (data) { - toast.success('Successful updated'); + toast.success( + tCommon('updatedSuccessfully', { item: 'Password' }) as string, + ); setTimeout(() => { window.location.reload(); }, 2000); @@ -64,6 +79,10 @@ const UserUpdate: React.FC< } }; + /** + * Handles canceling the update process. + * It reloads the page to reset any changes. + */ /* istanbul ignore next */ const cancelUpdate = (): void => { window.location.reload(); diff --git a/src/components/UserPortal/ChatRoom/ChatRoom.module.css b/src/components/UserPortal/ChatRoom/ChatRoom.module.css index 592004d523..5fc98351cd 100644 --- a/src/components/UserPortal/ChatRoom/ChatRoom.module.css +++ b/src/components/UserPortal/ChatRoom/ChatRoom.module.css @@ -1,7 +1,7 @@ .chatAreaContainer { padding: 10px; flex-grow: 1; - background-color: rgba(196, 255, 211, 0.3); + /* background-color: rgba(196, 255, 211, 0.3); */ } .backgroundWhite { @@ -11,3 +11,240 @@ .grey { color: grey; } + +.header { + position: sticky; + top: 0px; + background: white; +} + +.userInfo { + display: flex; + border-bottom: 1px solid black; + padding-bottom: 5px; + align-items: center; + margin-top: 5px; + gap: 10px; +} + +.contactImage { + width: 45px !important; + height: auto !important; + border-radius: 10px; + display: flex; + align-items: center; + justify-content: center; +} + +.messageSentContainer { + display: flex; + justify-content: flex-end; +} + +.messageReceivedContainer { + display: flex; + align-items: flex-end; +} + +.messageReceived { + border: 1px solid #c2c2c2; + border-radius: 8px 8px 8px 0px; + padding: 4px 6px; + margin: 4px 6px; + width: fit-content; + max-width: 75%; + min-width: 80px; + padding-bottom: 0; + display: flex; + justify-content: space-between; +} + +.messageSent { + border: 1px solid #c2c2c2; + border-radius: 8px 8px 0px 8px; + padding: 4px 6px; + margin: 4px 6px; + width: fit-content; + max-width: 75%; + background-color: rgba(196, 255, 211, 0.3); + min-width: 80px; + padding-bottom: 0; + display: flex; + justify-content: space-between; +} + +.userDetails { + display: flex; + align-items: center; + font-size: 14px; + gap: 6px; +} + +.userDetails .userImage { + height: 20px; + width: 20px; +} + +.replyTo { + border-left: 4px solid pink; + display: flex; + justify-content: space-between; + background-color: rgb(249, 249, 250); + padding: 6px 0px 4px 4px; + border-radius: 6px 6px 6px 6px; +} + +.replyToMessageContainer { + padding-left: 4px; +} + +.replyToMessageContainer p { + margin: 4px 0px 0px; +} + +.replyToMessage { + border-left: 4px solid pink; + border-radius: 6px; + margin: 6px 0px; + padding: 6px; + background-color: #dbf6db; +} + +.messageReceived .replyToMessage { + background-color: #f2f2f2; +} + +.messageTime { + font-size: 10px; + display: flex; + align-items: flex-end; + justify-content: flex-end; + margin-bottom: 0px; + margin-left: 6px; +} + +.messageContent { + margin-bottom: 0.5px; + display: flex; + align-items: flex-start; + flex-direction: column; + justify-content: center; +} + +.createChat { + border: none; + background-color: white; +} + +.chatMessages { + margin: 10px 0; +} + +.userDetails .subtitle { + font-size: 12px; + color: #959595; + margin: 0; +} + +.userDetails .title { + font-size: 18px; + margin: 0; +} + +.contactImage { + height: fit-content; +} + +.senderInfo { + margin: 2px 2px 0px 2px; + font-size: 12px; + font-weight: 600; +} + +.messageAttributes { + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: flex-end; +} + +.customToggle { + display: none; +} + +.customToggle, +.closeBtn { + padding: 0; + background: none; + border: none; + --bs-btn-active-bg: none; +} +.customToggle svg { + color: black; + font-size: 12px; +} + +.customToggle::after, +.closeBtn::after { + content: none; +} + +.closeBtn svg { + color: black; + font-size: 18px; +} + +.closeBtn { + padding: 2px 10px; +} + +.closeBtn:hover { + background-color: transparent; + border-color: transparent; +} + +.customToggle:hover, +.customToggle:focus, +.customToggle:active { + background: none; + border: none; +} + +.messageReceived:hover .customToggle { + display: block; +} + +.messageSent:hover .customToggle { + display: block; +} + +.messageSent:hover, +.messageReceived:hover { + padding: 0px 6px; +} + +.messageSent:target { + scroll-margin-top: 100px; + animation-name: test; + animation-duration: 1s; +} + +.messageReceived:target { + scroll-margin-top: 100px; + animation-name: test; + animation-duration: 1s; +} + +@keyframes test { + from { + background-color: white; + } + to { + background-color: rgb(82, 83, 81); + } +} + +a { + color: currentColor; + width: 100%; +} diff --git a/src/components/UserPortal/ChatRoom/ChatRoom.test.tsx b/src/components/UserPortal/ChatRoom/ChatRoom.test.tsx index 9b63779582..c808485132 100644 --- a/src/components/UserPortal/ChatRoom/ChatRoom.test.tsx +++ b/src/components/UserPortal/ChatRoom/ChatRoom.test.tsx @@ -1,17 +1,28 @@ import React from 'react'; -import { act, render, screen, fireEvent } from '@testing-library/react'; -import { MockedProvider } from '@apollo/react-testing'; +import { + act, + render, + screen, + fireEvent, + waitFor, +} from '@testing-library/react'; +import { MockSubscriptionLink, MockedProvider } from '@apollo/react-testing'; import { I18nextProvider } from 'react-i18next'; - import { BrowserRouter } from 'react-router-dom'; import { Provider } from 'react-redux'; import { store } from 'state/store'; import i18nForTest from 'utils/i18nForTest'; +import { CHATS_LIST, CHAT_BY_ID } from 'GraphQl/Queries/PlugInQueries'; +import { + MESSAGE_SENT_TO_CHAT, + SEND_MESSAGE_TO_CHAT, +} from 'GraphQl/Mutations/OrganizationMutations'; +import ChatRoom from './ChatRoom'; +import { useLocalStorage } from 'utils/useLocalstorage'; import { StaticMockLink } from 'utils/StaticMockLink'; -import ContactCard from './ChatRoom'; -const link = new StaticMockLink([], true); +const { setItem } = useLocalStorage(); async function wait(ms = 100): Promise { await act(() => { @@ -21,29 +32,1200 @@ async function wait(ms = 100): Promise { }); } +const MESSAGE_SENT_TO_CHAT_MOCK = [ + { + request: { + query: MESSAGE_SENT_TO_CHAT, + variables: { + userId: null, + }, + }, + result: { + data: { + messageSentToChat: { + _id: '668ec1f1364e03ac47a151', + createdAt: '2024-07-10T17:16:33.248Z', + chatMessageBelongsTo: { + _id: '1', + }, + messageContent: 'Test ', + replyTo: null, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, + { + request: { + query: MESSAGE_SENT_TO_CHAT, + variables: { + userId: '2', + }, + }, + result: { + data: { + messageSentToChat: { + _id: '668ec1f1df364e03ac47a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + chatMessageBelongsTo: { + _id: '1', + }, + replyTo: null, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, + { + request: { + query: MESSAGE_SENT_TO_CHAT, + variables: { + userId: '1', + }, + }, + result: { + data: { + messageSentToChat: { + _id: '668ec1f13603ac4697a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + chatMessageBelongsTo: { + _id: '1', + }, + replyTo: null, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, +]; + +const CHAT_BY_ID_QUERY_MOCK = [ + { + request: { + query: CHAT_BY_ID, + variables: { + id: '1', + }, + }, + result: { + data: { + chatById: { + _id: '1', + createdAt: '2345678903456', + isGroup: false, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: null, + name: '', + messages: [ + { + _id: '4', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + ], + }, + }, + }, + }, + { + request: { + query: CHAT_BY_ID, + variables: { + id: '1', + }, + }, + result: { + data: { + chatById: { + _id: '1', + isGroup: false, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: null, + name: '', + createdAt: '2345678903456', + messages: [ + { + _id: '4', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + ], + }, + }, + }, + }, + { + request: { + query: CHAT_BY_ID, + variables: { + id: '', + }, + }, + result: { + data: { + chatById: { + _id: '1', + isGroup: false, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: null, + name: '', + createdAt: '2345678903456', + messages: [ + { + _id: '4', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + ], + }, + }, + }, + }, +]; + +const CHATS_LIST_MOCK = [ + { + request: { + query: CHATS_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844efc814dd40fgh03db811c4', + isGroup: true, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: { + _id: 'pw3ertyuiophgfre45678', + name: 'rtyu', + }, + createdAt: '2345678903456', + name: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + { + _id: '3', + firstName: 'Test', + lastName: 'User1', + email: 'test1@example.com', + image: '', + }, + { + _id: '4', + firstName: 'Test', + lastName: 'User2', + email: 'test2@example.com', + image: '', + }, + { + _id: '5', + firstName: 'Test', + lastName: 'User4', + email: 'test4@example.com', + image: '', + }, + ], + }, + { + _id: '65844efc814ddgh4003db811c4', + isGroup: true, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: { + _id: 'pw3ertyuiophgfre45678', + name: 'rtyu', + }, + createdAt: '2345678903456', + name: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + { + _id: '3', + firstName: 'Test', + lastName: 'User1', + email: 'test1@example.com', + image: '', + }, + { + _id: '4', + firstName: 'Test', + lastName: 'User2', + email: 'test2@example.com', + image: '', + }, + { + _id: '5', + firstName: 'Test', + lastName: 'User4', + email: 'test4@example.com', + image: '', + }, + ], + }, + ], + }, + }, + }, + { + request: { + query: CHATS_LIST, + variables: { + id: '', + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844ghjefc814dd4003db811c4', + isGroup: true, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: { + _id: 'pw3ertyuiophgfre45678', + name: 'rtyu', + }, + createdAt: '2345678903456', + name: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + { + _id: '3', + firstName: 'Test', + lastName: 'User1', + email: 'test1@example.com', + image: '', + }, + { + _id: '4', + firstName: 'Test', + lastName: 'User2', + email: 'test2@example.com', + image: '', + }, + { + _id: '5', + firstName: 'Test', + lastName: 'User4', + email: 'test4@example.com', + image: '', + }, + ], + }, + { + _id: 'ujhgtrdtyuiop', + isGroup: true, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: { + _id: 'pw3ertyuiophgfre45678', + name: 'rtyu', + }, + createdAt: '2345678903456', + name: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + { + _id: '3', + firstName: 'Test', + lastName: 'User1', + email: 'test1@example.com', + image: '', + }, + { + _id: '4', + firstName: 'Test', + lastName: 'User2', + email: 'test2@example.com', + image: '', + }, + { + _id: '5', + firstName: 'Test', + lastName: 'User4', + email: 'test4@example.com', + image: '', + }, + ], + }, + ], + }, + }, + }, + { + request: { + query: CHATS_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844efc814dhjmkdftyd4003db811c4', + isGroup: true, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: { + _id: 'pw3ertyuiophgfre45678', + name: 'rtyu', + }, + createdAt: '2345678903456', + name: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + { + _id: '3', + firstName: 'Test', + lastName: 'User1', + email: 'test1@example.com', + image: '', + }, + { + _id: '4', + firstName: 'Test', + lastName: 'User2', + email: 'test2@example.com', + image: '', + }, + { + _id: '5', + firstName: 'Test', + lastName: 'User4', + email: 'test4@example.com', + image: '', + }, + ], + }, + { + _id: '65844ewsedrffc814dd4003db811c4', + isGroup: true, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: { + _id: 'pw3ertyuiophgfre45678', + name: 'rtyu', + }, + createdAt: '2345678903456', + name: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + { + _id: '3', + firstName: 'Test', + lastName: 'User1', + email: 'test1@example.com', + image: '', + }, + { + _id: '4', + firstName: 'Test', + lastName: 'User2', + email: 'test2@example.com', + image: '', + }, + { + _id: '5', + firstName: 'Test', + lastName: 'User4', + email: 'test4@example.com', + image: '', + }, + ], + }, + ], + }, + }, + }, +]; + +const GROUP_CHAT_BY_ID_QUERY_MOCK = [ + { + request: { + query: CHAT_BY_ID, + variables: { + id: '', + }, + }, + result: { + data: { + chatById: { + _id: '65844efc814dd4003db811c4', + isGroup: true, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: { + _id: 'pw3ertyuiophgfre45678', + name: 'rtyu', + }, + createdAt: '2345678903456', + name: 'Test Group Chat', + messages: [ + { + _id: '2', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + { + _id: '3', + firstName: 'Test', + lastName: 'User1', + email: 'test1@example.com', + image: '', + }, + { + _id: '4', + firstName: 'Test', + lastName: 'User2', + email: 'test2@example.com', + image: '', + }, + { + _id: '5', + firstName: 'Test', + lastName: 'User4', + email: 'test4@example.com', + image: '', + }, + ], + }, + }, + }, + }, + { + request: { + query: CHAT_BY_ID, + variables: { + id: '1', + }, + }, + result: { + data: { + chatById: { + _id: '65844efc814dd4003db811c4', + isGroup: true, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: { + _id: 'pw3ertyuiophgfre45678', + name: 'rtyu', + }, + createdAt: '2345678903456', + name: 'Test Group Chat', + messages: [ + { + _id: '1', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + { + _id: '3', + firstName: 'Test', + lastName: 'User1', + email: 'test1@example.com', + image: '', + }, + { + _id: '4', + firstName: 'Test', + lastName: 'User2', + email: 'test2@example.com', + image: '', + }, + { + _id: '5', + firstName: 'Test', + lastName: 'User4', + email: 'test4@example.com', + image: '', + }, + ], + }, + }, + }, + }, + { + request: { + query: CHAT_BY_ID, + variables: { + id: '1', + }, + }, + result: { + data: { + chatById: { + _id: '65844efc814dd4003db811c4', + isGroup: true, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: { + _id: 'pw3ertyuiophgfre45678', + name: 'rtyu', + }, + createdAt: '2345678903456', + name: 'Test Group Chat', + messages: [ + { + _id: '1', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + { + _id: '3', + firstName: 'Test', + lastName: 'User1', + email: 'test1@example.com', + image: '', + }, + { + _id: '4', + firstName: 'Test', + lastName: 'User2', + email: 'test2@example.com', + image: '', + }, + { + _id: '5', + firstName: 'Test', + lastName: 'User4', + email: 'test4@example.com', + image: '', + }, + ], + }, + }, + }, + }, +]; + +const SEND_MESSAGE_TO_CHAT_MOCK = [ + { + request: { + query: SEND_MESSAGE_TO_CHAT, + variables: { + chatId: '1', + replyTo: '4', + messageContent: 'Test reply message', + }, + }, + result: { + data: { + sendMessageToChat: { + _id: '668ec1f1364e03ac47a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + replyTo: null, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, + { + request: { + query: SEND_MESSAGE_TO_CHAT, + variables: { + chatId: '1', + replyTo: '4', + messageContent: 'Test reply message', + }, + }, + result: { + data: { + sendMessageToChat: { + _id: '668ec1f1364e03ac47a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + replyTo: null, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, + { + request: { + query: SEND_MESSAGE_TO_CHAT, + variables: { + chatId: '1', + replyTo: '1', + messageContent: 'Test reply message', + }, + }, + result: { + data: { + sendMessageToChat: { + _id: '668ec1f1364e03ac47a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + replyTo: null, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, + { + request: { + query: SEND_MESSAGE_TO_CHAT, + variables: { + chatId: '1', + replyTo: undefined, + messageContent: 'Hello', + }, + }, + result: { + data: { + sendMessageToChat: { + _id: '668ec1f1364e03ac47a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + replyTo: null, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, + { + request: { + query: SEND_MESSAGE_TO_CHAT, + variables: { + chatId: '1', + replyTo: '345678', + messageContent: 'Test reply message', + }, + }, + result: { + data: { + sendMessageToChat: { + _id: '668ec1f1364e03ac47a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + replyTo: null, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, + { + request: { + query: SEND_MESSAGE_TO_CHAT, + variables: { + chatId: '1', + replyTo: undefined, + messageContent: 'Test message', + }, + }, + result: { + data: { + sendMessageToChat: { + _id: '668ec1f1364e03ac47a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + replyTo: null, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, +]; + describe('Testing Chatroom Component [User Portal]', () => { - test('Component should be rendered properly if the selectedContact is undefined', async () => { + window.HTMLElement.prototype.scrollIntoView = jest.fn(); + + test('Chat room should display fallback content if no chat is active', async () => { + const mocks = [ + ...MESSAGE_SENT_TO_CHAT_MOCK, + ...CHAT_BY_ID_QUERY_MOCK, + ...CHATS_LIST_MOCK, + ...SEND_MESSAGE_TO_CHAT_MOCK, + ]; render( - + - + , ); await wait(); + expect(await screen.findByTestId('noChatSelected')).toBeInTheDocument(); }); - test('Component should be rendered properly if selectedContact is not undefined', async () => { + test('Selected contact is direct chat', async () => { + const link = new MockSubscriptionLink(); + const mocks = [ + ...MESSAGE_SENT_TO_CHAT_MOCK, + ...CHAT_BY_ID_QUERY_MOCK, + ...CHATS_LIST_MOCK, + ...SEND_MESSAGE_TO_CHAT_MOCK, + ]; render( - + - + @@ -52,21 +1234,353 @@ describe('Testing Chatroom Component [User Portal]', () => { await wait(); }); - test('Message should change when the user types in the input', async () => { + test('send message direct chat', async () => { + setItem('userId', '2'); + const mocks = [ + ...MESSAGE_SENT_TO_CHAT_MOCK, + ...CHAT_BY_ID_QUERY_MOCK, + ...CHATS_LIST_MOCK, + ...GROUP_CHAT_BY_ID_QUERY_MOCK, + ...SEND_MESSAGE_TO_CHAT_MOCK, + ]; + const link2 = new StaticMockLink(mocks, true); render( - + - + , ); - const input = screen.getByTestId('messageInput') as HTMLInputElement; - fireEvent.change(input, { target: { value: 'Hello' } }); + await wait(); + + const input = (await screen.findByTestId( + 'messageInput', + )) as HTMLInputElement; + act(() => { + fireEvent.change(input, { target: { value: 'Hello' } }); + }); expect(input.value).toBe('Hello'); + + const sendBtn = await screen.findByTestId('sendMessage'); + + expect(sendBtn).toBeInTheDocument(); + act(() => { + fireEvent.click(sendBtn); + }); + await waitFor(() => { + expect(input.value).toBeFalsy(); + }); + + const messages = await screen.findAllByTestId('message'); + + console.log('MESSAGES', messages); + + expect(messages.length).not.toBe(0); + + act(() => { + fireEvent.mouseOver(messages[0]); + }); + + await waitFor(async () => { + expect(await screen.findByTestId('moreOptions')).toBeInTheDocument(); + }); + + const moreOptionsBtn = await screen.findByTestId('dropdown'); + act(() => { + fireEvent.click(moreOptionsBtn); + }); + + const replyBtn = await screen.findByTestId('replyBtn'); + + act(() => { + fireEvent.click(replyBtn); + }); + + const replyMsg = await screen.findByTestId('replyMsg'); + + await waitFor(() => { + expect(replyMsg).toBeInTheDocument(); + }); + + act(() => { + fireEvent.change(input, { target: { value: 'Test reply message' } }); + }); + expect(input.value).toBe('Test reply message'); + + act(() => { + fireEvent.click(sendBtn); + }); + + await wait(400); + }); + + test('send message direct chat when userId is different', async () => { + setItem('userId', '8'); + const mocks = [ + ...GROUP_CHAT_BY_ID_QUERY_MOCK, + ...MESSAGE_SENT_TO_CHAT_MOCK, + ...CHAT_BY_ID_QUERY_MOCK, + ...CHATS_LIST_MOCK, + ...SEND_MESSAGE_TO_CHAT_MOCK, + ]; + const link2 = new StaticMockLink(mocks, true); + render( + + + + + + + + + , + ); + await wait(); + + const input = (await screen.findByTestId( + 'messageInput', + )) as HTMLInputElement; + + act(() => { + fireEvent.change(input, { target: { value: 'Hello' } }); + }); + expect(input.value).toBe('Hello'); + + const sendBtn = await screen.findByTestId('sendMessage'); + + expect(sendBtn).toBeInTheDocument(); + act(() => { + fireEvent.click(sendBtn); + }); + await waitFor(() => { + expect(input.value).toBeFalsy(); + }); + + const messages = await screen.findAllByTestId('message'); + + console.log('MESSAGES', messages); + + expect(messages.length).not.toBe(0); + + act(() => { + fireEvent.mouseOver(messages[0]); + }); + + await waitFor(async () => { + expect(await screen.findByTestId('moreOptions')).toBeInTheDocument(); + }); + + const moreOptionsBtn = await screen.findByTestId('dropdown'); + act(() => { + fireEvent.click(moreOptionsBtn); + }); + + const replyBtn = await screen.findByTestId('replyBtn'); + + act(() => { + fireEvent.click(replyBtn); + }); + + const replyMsg = await screen.findByTestId('replyMsg'); + + await waitFor(() => { + expect(replyMsg).toBeInTheDocument(); + }); + + act(() => { + fireEvent.change(input, { target: { value: 'Test reply message' } }); + }); + expect(input.value).toBe('Test reply message'); + + act(() => { + fireEvent.click(sendBtn); + }); + + await wait(400); + }); + + test('Selected contact is group chat', async () => { + const mocks = [ + ...MESSAGE_SENT_TO_CHAT_MOCK, + ...CHAT_BY_ID_QUERY_MOCK, + ...CHATS_LIST_MOCK, + ...SEND_MESSAGE_TO_CHAT_MOCK, + ]; + render( + + + + + + + + + , + ); + await wait(); + }); + + test('send message group chat', async () => { + const mocks = [ + ...MESSAGE_SENT_TO_CHAT_MOCK, + ...CHAT_BY_ID_QUERY_MOCK, + ...CHATS_LIST_MOCK, + ...SEND_MESSAGE_TO_CHAT_MOCK, + ]; + render( + + + + + + + + + , + ); + await wait(); + + const input = (await screen.findByTestId( + 'messageInput', + )) as HTMLInputElement; + + act(() => { + fireEvent.change(input, { target: { value: 'Test message' } }); + }); + expect(input.value).toBe('Test message'); + + const sendBtn = await screen.findByTestId('sendMessage'); + + expect(sendBtn).toBeInTheDocument(); + act(() => { + fireEvent.click(sendBtn); + }); + await waitFor(() => { + expect(input.value).toBeFalsy(); + }); + + const messages = await screen.findAllByTestId('message'); + + expect(messages.length).not.toBe(0); + + act(() => { + fireEvent.mouseOver(messages[0]); + }); + + expect(await screen.findByTestId('moreOptions')).toBeInTheDocument(); + + const moreOptionsBtn = await screen.findByTestId('dropdown'); + act(() => { + fireEvent.click(moreOptionsBtn); + }); + + const replyBtn = await screen.findByTestId('replyBtn'); + + act(() => { + fireEvent.click(replyBtn); + }); + + const replyMsg = await screen.findByTestId('replyMsg'); + + await waitFor(() => { + expect(replyMsg).toBeInTheDocument(); + }); + + act(() => { + fireEvent.change(input, { target: { value: 'Test reply message' } }); + }); + expect(input.value).toBe('Test reply message'); + + const closeReplyBtn = await screen.findByTestId('closeReply'); + + expect(closeReplyBtn).toBeInTheDocument(); + + fireEvent.click(closeReplyBtn); + + await wait(500); + }); + + test('reply to message', async () => { + const mocks = [ + ...MESSAGE_SENT_TO_CHAT_MOCK, + ...CHAT_BY_ID_QUERY_MOCK, + ...CHATS_LIST_MOCK, + ...SEND_MESSAGE_TO_CHAT_MOCK, + ]; + const link2 = new StaticMockLink(mocks, true); + render( + + + + + + + + + , + ); + await wait(); + + const input = (await screen.findByTestId( + 'messageInput', + )) as HTMLInputElement; + + act(() => { + fireEvent.change(input, { target: { value: 'Test message' } }); + }); + expect(input.value).toBe('Test message'); + + const sendBtn = await screen.findByTestId('sendMessage'); + + expect(sendBtn).toBeInTheDocument(); + act(() => { + fireEvent.click(sendBtn); + }); + await waitFor(() => { + expect(input.value).toBeFalsy(); + }); + + const messages = await screen.findAllByTestId('message'); + + expect(messages.length).not.toBe(0); + + act(() => { + fireEvent.mouseOver(messages[0]); + }); + + expect(await screen.findByTestId('moreOptions')).toBeInTheDocument(); + + const moreOptionsBtn = await screen.findByTestId('dropdown'); + act(() => { + fireEvent.click(moreOptionsBtn); + }); + + const replyBtn = await screen.findByTestId('replyBtn'); + + act(() => { + fireEvent.click(replyBtn); + }); + + const replyMsg = await screen.findByTestId('replyMsg'); + + await waitFor(() => { + expect(replyMsg).toBeInTheDocument(); + }); + + act(() => { + fireEvent.change(input, { target: { value: 'Test reply message' } }); + }); + expect(input.value).toBe('Test reply message'); + + act(() => { + fireEvent.click(sendBtn); + }); + + await wait(400); }); }); diff --git a/src/components/UserPortal/ChatRoom/ChatRoom.tsx b/src/components/UserPortal/ChatRoom/ChatRoom.tsx index ac65a76199..c23244a314 100644 --- a/src/components/UserPortal/ChatRoom/ChatRoom.tsx +++ b/src/components/UserPortal/ChatRoom/ChatRoom.tsx @@ -1,66 +1,357 @@ -import React from 'react'; +import React, { useEffect, useRef, useState } from 'react'; import type { ChangeEvent } from 'react'; -import { Paper } from '@mui/material'; import SendIcon from '@mui/icons-material/Send'; -import { Button, Form, InputGroup } from 'react-bootstrap'; +import { Button, Dropdown, Form, InputGroup } from 'react-bootstrap'; import styles from './ChatRoom.module.css'; import PermContactCalendarIcon from '@mui/icons-material/PermContactCalendar'; import { useTranslation } from 'react-i18next'; +import { CHAT_BY_ID } from 'GraphQl/Queries/PlugInQueries'; +import { useMutation, useQuery, useSubscription } from '@apollo/client'; +import { + MESSAGE_SENT_TO_CHAT, + SEND_MESSAGE_TO_CHAT, +} from 'GraphQl/Mutations/OrganizationMutations'; +import useLocalStorage from 'utils/useLocalstorage'; +import Avatar from 'components/Avatar/Avatar'; +import { MoreVert, Close } from '@mui/icons-material'; interface InterfaceChatRoomProps { selectedContact: string; } +/** + * A chat room component that displays messages and a message input field. + * + * This component shows a list of messages between the user and a selected contact. + * If no contact is selected, it displays a placeholder with an icon and a message asking the user to select a contact. + * + * @param props - The properties passed to the component. + * @param selectedContact - The ID or name of the currently selected contact. If empty, a placeholder is shown. + * + * @returns The rendered chat room component. + */ + +type DirectMessage = { + _id: string; + createdAt: Date; + sender: { + _id: string; + firstName: string; + lastName: string; + image: string; + }; + replyTo: + | { + _id: string; + createdAt: Date; + sender: { + _id: string; + firstName: string; + lastName: string; + image: string; + }; + messageContent: string; + receiver: { + _id: string; + firstName: string; + lastName: string; + }; + } + | undefined; + messageContent: string; + type: string; +}; + +type Chat = { + _id: string; + isGroup: boolean; + name?: string; + image?: string; + messages: DirectMessage[]; + users: { + _id: string; + firstName: string; + lastName: string; + email: string; + }[]; +}; + export default function chatRoom(props: InterfaceChatRoomProps): JSX.Element { + // Translation hook for text in different languages const { t } = useTranslation('translation', { keyPrefix: 'userChatRoom', }); + const isMountedRef = useRef(true); + + useEffect(() => { + return () => { + isMountedRef.current = false; + }; + }, []); - const [newMessage, setNewMessage] = React.useState(''); + const { getItem } = useLocalStorage(); + const userId = getItem('userId'); + const [chatTitle, setChatTitle] = useState(''); + const [chatSubtitle, setChatSubtitle] = useState(''); + const [newMessage, setNewMessage] = useState(''); + const [chat, setChat] = useState(); + const [replyToDirectMessage, setReplyToDirectMessage] = + useState(null); + /** + * Handles changes to the new message input field. + * + * Updates the state with the current value of the input field whenever it changes. + * + * @param e - The event triggered by the input field change. + */ const handleNewMessageChange = (e: ChangeEvent): void => { const newMessageValue = e.target.value; - setNewMessage(newMessageValue); }; + const [sendMessageToChat] = useMutation(SEND_MESSAGE_TO_CHAT, { + variables: { + chatId: props.selectedContact, + replyTo: replyToDirectMessage?._id, + messageContent: newMessage, + }, + }); + + const { data: chatData, refetch: chatRefetch } = useQuery(CHAT_BY_ID, { + variables: { + id: props.selectedContact, + }, + }); + + useEffect(() => { + chatRefetch(); + }, [props.selectedContact]); + + useEffect(() => { + if (chatData) { + const chat = chatData.chatById; + setChat(chat); + if (chat.isGroup) { + setChatTitle(chat.name); + setChatSubtitle(`${chat.users.length} members`); + } else { + const otherUser = chat.users.find( + (user: { _id: string }) => user._id !== userId, + ); + if (otherUser) { + setChatTitle(`${otherUser.firstName} ${otherUser.lastName}`); + setChatSubtitle(otherUser.email); + } + } + } + }, [chatData]); + + const sendMessage = async (): Promise => { + await sendMessageToChat(); + await chatRefetch(); + setReplyToDirectMessage(null); + setNewMessage(''); + }; + + useSubscription(MESSAGE_SENT_TO_CHAT, { + variables: { + userId: userId, + }, + onData: (messageSubscriptionData) => { + if ( + messageSubscriptionData?.data.data.messageSentToChat && + messageSubscriptionData?.data.data.messageSentToChat + .chatMessageBelongsTo['_id'] == props.selectedContact + ) { + chatRefetch(); + } else { + chatRefetch({ + id: messageSubscriptionData?.data.data.messageSentToChat + .chatMessageBelongsTo['_id'], + }); + } + }, + }); + + useEffect(() => { + document + .getElementById('chat-area') + ?.lastElementChild?.scrollIntoView({ block: 'end' }); + }); + return ( -
    +
    {!props.selectedContact ? (
    -
    {t('selectContact')}
    +
    {t('selectContact')}
    ) : ( <> +
    +
    + +
    +

    {chatTitle}

    +

    {chatSubtitle}

    +
    +
    +
    - - My message - - - Other message - +
    + {!!chat?.messages.length && ( +
    + {chat?.messages.map((message: DirectMessage) => { + return ( +
    + {chat.isGroup && + message.sender._id !== userId && + (message.sender?.image ? ( + {message.sender.image} + ) : ( + + ))} +
    + + {chat.isGroup && message.sender._id !== userId && ( +

    + {message.sender.firstName + + ' ' + + message.sender.lastName} +

    + )} + {message.replyTo && ( + +
    +

    + {message.replyTo.sender.firstName + + ' ' + + message.replyTo.sender.lastName} +

    + {message.replyTo.messageContent} +
    +
    + )} + {message.messageContent} +
    +
    + + + + + + { + setReplyToDirectMessage(message); + }} + data-testid="replyBtn" + > + Reply + + + + + {new Date(message?.createdAt).toLocaleTimeString( + 'it-IT', + { + hour: '2-digit', + minute: '2-digit', + }, + )} + +
    +
    +
    + ); + })} +
    + )} +
    -
    +
    + {!!replyToDirectMessage?._id && ( +
    +
    +
    + + + {replyToDirectMessage.sender.firstName + + ' ' + + replyToDirectMessage.sender.lastName} + +
    +

    {replyToDirectMessage.messageContent}

    +
    + + +
    + )} - diff --git a/src/components/UserPortal/CommentCard/CommentCard.test.tsx b/src/components/UserPortal/CommentCard/CommentCard.test.tsx index 35b81167fc..f02e5a606a 100644 --- a/src/components/UserPortal/CommentCard/CommentCard.test.tsx +++ b/src/components/UserPortal/CommentCard/CommentCard.test.tsx @@ -1,6 +1,6 @@ -import React from 'react'; +import React, { act } from 'react'; import { MockedProvider } from '@apollo/react-testing'; -import { act, render, screen } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import { I18nextProvider } from 'react-i18next'; import { Provider } from 'react-redux'; import { BrowserRouter } from 'react-router-dom'; diff --git a/src/components/UserPortal/CommentCard/CommentCard.tsx b/src/components/UserPortal/CommentCard/CommentCard.tsx index 57cc6a1cf4..9e8c46d241 100644 --- a/src/components/UserPortal/CommentCard/CommentCard.tsx +++ b/src/components/UserPortal/CommentCard/CommentCard.tsx @@ -27,19 +27,55 @@ interface InterfaceCommentCardProps { handleDislikeComment: (commentId: string) => void; } +/** + * Displays a card for a single comment with options to like or dislike the comment. + * + * Shows the commenter's name, the comment text, and the number of likes. + * Allows the user to like or dislike the comment. The button icon changes based on whether the comment is liked by the user. + * + * @param props - The properties passed to the component. + * @param id - The unique identifier of the comment. + * @param creator - Information about the creator of the comment. + * @param id - The unique identifier of the creator. + * @param firstName - The first name of the creator. + * @param lastName - The last name of the creator. + * @param email - The email address of the creator. + * @param likeCount - The current number of likes for the comment. + * @param likedBy - An array of users who have liked the comment. + * @param text - The text content of the comment. + * @param handleLikeComment - Function to call when the user likes the comment. + * @param handleDislikeComment - Function to call when the user dislikes the comment. + * + * @returns The rendered comment card component. + */ function commentCard(props: InterfaceCommentCardProps): JSX.Element { + // Full name of the comment creator const creatorName = `${props.creator.firstName} ${props.creator.lastName}`; + // Hook to get user ID from local storage const { getItem } = useLocalStorage(); const userId = getItem('userId'); + + // Check if the current user has liked the comment const likedByUser = props.likedBy.some((likedBy) => likedBy.id === userId); + // State to track the number of likes and if the comment is liked by the user const [likes, setLikes] = React.useState(props.likeCount); const [isLikedByUser, setIsLikedByUser] = React.useState(likedByUser); + + // Mutation hooks for liking and unliking comments const [likeComment, { loading: likeLoading }] = useMutation(LIKE_COMMENT); const [unlikeComment, { loading: unlikeLoading }] = useMutation(UNLIKE_COMMENT); + /** + * Toggles the like status of the comment. + * + * If the comment is already liked by the user, it will be unliked. Otherwise, it will be liked. + * Updates the number of likes and the like status accordingly. + * + * @returns A promise that resolves when the like/unlike operation is complete. + */ const handleToggleLike = async (): Promise => { if (isLikedByUser) { try { @@ -54,9 +90,9 @@ function commentCard(props: InterfaceCommentCardProps): JSX.Element { setIsLikedByUser(false); props.handleDislikeComment(props.id); } - } catch (error: any) { + } catch (error: unknown) { /* istanbul ignore next */ - toast.error(error); + toast.error(error as string); } } else { try { @@ -71,9 +107,9 @@ function commentCard(props: InterfaceCommentCardProps): JSX.Element { setIsLikedByUser(true); props.handleLikeComment(props.id); } - } catch (error: any) { + } catch (error: unknown) { /* istanbul ignore next */ - toast.error(error); + toast.error(error as string); } } }; diff --git a/src/components/UserPortal/ContactCard/ContactCard.module.css b/src/components/UserPortal/ContactCard/ContactCard.module.css index d722a3a302..19d66596c9 100644 --- a/src/components/UserPortal/ContactCard/ContactCard.module.css +++ b/src/components/UserPortal/ContactCard/ContactCard.module.css @@ -1,31 +1,35 @@ .contact { display: flex; flex-direction: row; - padding: 10px 10px; + padding: 5px 10px; cursor: pointer; border-radius: 10px; - margin-bottom: 10px; - border: 2px solid #f5f5f5; + /* margin-bottom: 10px; */ + /* border: 2px solid #f5f5f5; */ } .contactImage { - width: 50px; - height: auto; + width: 45px !important; + height: auto !important; border-radius: 10px; + display: flex; + align-items: center; + justify-content: center; } .contactNameContainer { display: flex; flex-direction: column; padding: 0px 10px; + justify-content: center; } .grey { color: grey; } -.bgGrey { - background-color: #f5f5f5; +.bgGreen { + background-color: rgba(196, 255, 211, 0.3); } .bgWhite { diff --git a/src/components/UserPortal/ContactCard/ContactCard.test.tsx b/src/components/UserPortal/ContactCard/ContactCard.test.tsx index 7e7530bc58..05a6a0a530 100644 --- a/src/components/UserPortal/ContactCard/ContactCard.test.tsx +++ b/src/components/UserPortal/ContactCard/ContactCard.test.tsx @@ -1,5 +1,5 @@ -import React from 'react'; -import { act, render, screen } from '@testing-library/react'; +import React, { act } from 'react'; +import { render, screen } from '@testing-library/react'; import { MockedProvider } from '@apollo/react-testing'; import { I18nextProvider } from 'react-i18next'; @@ -23,13 +23,15 @@ async function wait(ms = 100): Promise { let props = { id: '1', - firstName: 'Noble', - lastName: 'Mittal', + title: 'Disha Talreja', + subtitle: 'disha@example.com', email: 'noble@mittal.com', + isGroup: false, image: '', selectedContact: '', + type: '', setSelectedContact: jest.fn(), - setSelectedContactName: jest.fn(), + setSelectedChatType: jest.fn(), }; describe('Testing ContactCard Component [User Portal]', () => { @@ -94,6 +96,7 @@ describe('Testing ContactCard Component [User Portal]', () => { props = { ...props, selectedContact: '1', + isGroup: true, }; render( diff --git a/src/components/UserPortal/ContactCard/ContactCard.tsx b/src/components/UserPortal/ContactCard/ContactCard.tsx index be4247205b..ef6bf2c9d5 100644 --- a/src/components/UserPortal/ContactCard/ContactCard.tsx +++ b/src/components/UserPortal/ContactCard/ContactCard.tsx @@ -4,27 +4,41 @@ import Avatar from 'components/Avatar/Avatar'; interface InterfaceContactCardProps { id: string; - firstName: string; - lastName: string; - email: string; + title: string; image: string; selectedContact: string; setSelectedContact: React.Dispatch>; - setSelectedContactName: React.Dispatch>; + isGroup: boolean; } +/** + * Displays a card for a contact in a contact list. + * + * Shows the contact's name, email, and an image or avatar. + * The card changes background color based on whether it is selected. + * Clicking on the card sets it as the selected contact and updates the contact name. + * + * @param props - The properties passed to the component. + * @param id - The unique identifier of the contact. + * @param firstName - The first name of the contact. + * @param lastName - The last name of the contact. + * @param email - The email address of the contact. + * @param image - The URL of the contact's image. + * @param selectedContact - The ID of the currently selected contact. + * @param setSelectedContact - Function to set the ID of the selected contact. + * @param setSelectedContactName - Function to set the name of the selected contact. + * + * @returns The rendered contact card component. + */ function contactCard(props: InterfaceContactCardProps): JSX.Element { - const contactName = `${props.firstName} ${props.lastName}`; - const handleSelectedContactChange = (): void => { props.setSelectedContact(props.id); - props.setSelectedContactName(contactName); }; - const [isSelected, setIsSelected] = React.useState( props.selectedContact === props.id, ); + // Update selection state when the selected contact changes React.useEffect(() => { setIsSelected(props.selectedContact === props.id); }, [props.selectedContact]); @@ -33,7 +47,7 @@ function contactCard(props: InterfaceContactCardProps): JSX.Element { <>
    ) : ( )}
    - {contactName} - {props.email} + {props.title}
    diff --git a/src/components/UserPortal/CreateDirectChat/CreateDirectChat.module.css b/src/components/UserPortal/CreateDirectChat/CreateDirectChat.module.css new file mode 100644 index 0000000000..3795e402fa --- /dev/null +++ b/src/components/UserPortal/CreateDirectChat/CreateDirectChat.module.css @@ -0,0 +1,9 @@ +.userData { + height: 400px; + overflow-y: scroll; + overflow-x: hidden !important; +} + +.modalContent { + width: 530px; +} diff --git a/src/components/UserPortal/CreateDirectChat/CreateDirectChat.test.tsx b/src/components/UserPortal/CreateDirectChat/CreateDirectChat.test.tsx new file mode 100644 index 0000000000..e3e2eae75c --- /dev/null +++ b/src/components/UserPortal/CreateDirectChat/CreateDirectChat.test.tsx @@ -0,0 +1,1496 @@ +import React from 'react'; +import { + act, + fireEvent, + render, + screen, + waitFor, +} from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import { I18nextProvider, useTranslation } from 'react-i18next'; +import { USERS_CONNECTION_LIST } from 'GraphQl/Queries/Queries'; +import { BrowserRouter } from 'react-router-dom'; +import { Provider } from 'react-redux'; +import { store } from 'state/store'; +import i18nForTest from 'utils/i18nForTest'; +import Chat from '../../../screens/UserPortal/Chat/Chat'; +import { + CREATE_CHAT, + MESSAGE_SENT_TO_CHAT, +} from 'GraphQl/Mutations/OrganizationMutations'; +import { CHATS_LIST, CHAT_BY_ID } from 'GraphQl/Queries/PlugInQueries'; +import useLocalStorage from 'utils/useLocalstorage'; + +const { setItem } = useLocalStorage(); + +const UserConnectionListMock = [ + { + request: { + query: USERS_CONNECTION_LIST, + variables: { + firstName_contains: '', + lastName_contains: '', + }, + }, + result: { + data: { + users: [ + { + user: { + firstName: 'Deanne', + lastName: 'Marks', + image: null, + _id: '6589389d2caa9d8d69087487', + email: 'testuser8@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + organizationsBlockedBy: [], + joinedOrganizations: [ + { + _id: '6537904485008f171cf29924', + name: 'Unity Foundation', + image: null, + address: { + city: 'Queens', + countryCode: 'US', + dependentLocality: 'Some Dependent Locality', + line1: '123 Coffee Street', + line2: 'Apartment 501', + postalCode: '11427', + sortingCode: 'ABC-133', + state: 'NYC', + __typename: 'Address', + }, + createdAt: '2023-04-13T05:16:52.827Z', + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + __typename: 'Organization', + }, + { + _id: '6637904485008f171cf29924', + name: 'Unity Foundation', + image: null, + address: { + city: 'Staten Island', + countryCode: 'US', + dependentLocality: 'Some Dependent Locality', + line1: '123 church Street', + line2: 'Apartment 499', + postalCode: '10301', + sortingCode: 'ABC-122', + state: 'NYC', + __typename: 'Address', + }, + createdAt: '2023-04-13T05:16:52.827Z', + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + __typename: 'Organization', + }, + { + _id: '6737904485008f171cf29924', + name: 'Unity Foundation', + image: null, + address: { + city: 'Brooklyn', + countryCode: 'US', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Main Street', + line2: 'Apt 456', + postalCode: '10004', + sortingCode: 'ABC-789', + state: 'NY', + __typename: 'Address', + }, + createdAt: '2023-04-13T05:16:52.827Z', + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + __typename: 'Organization', + }, + { + _id: '6437904485008f171cf29924', + name: 'Unity Foundation', + image: null, + address: { + city: 'Bronx', + countryCode: 'US', + dependentLocality: 'Some Dependent Locality', + line1: '123 Random Street', + line2: 'Apartment 456', + postalCode: '10451', + sortingCode: 'ABC-123', + state: 'NYC', + __typename: 'Address', + }, + createdAt: '2023-04-13T05:16:52.827Z', + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + __typename: 'Organization', + }, + ], + __typename: 'User', + }, + appUserProfile: { + _id: '64378abd85308f171cf2993d', + adminFor: [], + isSuperAdmin: false, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + __typename: 'AppUserProfile', + }, + __typename: 'UserData', + }, + ], + }, + }, + }, + { + request: { + query: USERS_CONNECTION_LIST, + variables: { + firstName_contains: 'Disha', + lastName_contains: '', + }, + }, + result: { + data: { + users: [ + { + user: { + firstName: 'Deanne', + lastName: 'Marks', + image: null, + _id: '6589389d2caa9d8d69087487', + email: 'testuser8@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + organizationsBlockedBy: [], + joinedOrganizations: [ + { + _id: '6537904485008f171cf29924', + name: 'Unity Foundation', + image: null, + address: { + city: 'Queens', + countryCode: 'US', + dependentLocality: 'Some Dependent Locality', + line1: '123 Coffee Street', + line2: 'Apartment 501', + postalCode: '11427', + sortingCode: 'ABC-133', + state: 'NYC', + __typename: 'Address', + }, + createdAt: '2023-04-13T05:16:52.827Z', + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + __typename: 'Organization', + }, + { + _id: '6637904485008f171cf29924', + name: 'Unity Foundation', + image: null, + address: { + city: 'Staten Island', + countryCode: 'US', + dependentLocality: 'Some Dependent Locality', + line1: '123 church Street', + line2: 'Apartment 499', + postalCode: '10301', + sortingCode: 'ABC-122', + state: 'NYC', + __typename: 'Address', + }, + createdAt: '2023-04-13T05:16:52.827Z', + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + __typename: 'Organization', + }, + { + _id: '6737904485008f171cf29924', + name: 'Unity Foundation', + image: null, + address: { + city: 'Brooklyn', + countryCode: 'US', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Main Street', + line2: 'Apt 456', + postalCode: '10004', + sortingCode: 'ABC-789', + state: 'NY', + __typename: 'Address', + }, + createdAt: '2023-04-13T05:16:52.827Z', + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + __typename: 'Organization', + }, + { + _id: '6437904485008f171cf29924', + name: 'Unity Foundation', + image: null, + address: { + city: 'Bronx', + countryCode: 'US', + dependentLocality: 'Some Dependent Locality', + line1: '123 Random Street', + line2: 'Apartment 456', + postalCode: '10451', + sortingCode: 'ABC-123', + state: 'NYC', + __typename: 'Address', + }, + createdAt: '2023-04-13T05:16:52.827Z', + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + __typename: 'Organization', + }, + ], + __typename: 'User', + }, + appUserProfile: { + _id: '64378abd85308f171cf2993d', + adminFor: [], + isSuperAdmin: false, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + __typename: 'AppUserProfile', + }, + __typename: 'UserData', + }, + ], + }, + }, + }, +]; + +const MESSAGE_SENT_TO_CHAT_MOCK = [ + { + request: { + query: MESSAGE_SENT_TO_CHAT, + variables: { + userId: null, + }, + }, + result: { + data: { + messageSentToChat: { + _id: '668ec1f1364e03ac47a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + type: 'STRING', + replyTo: null, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, + { + request: { + query: MESSAGE_SENT_TO_CHAT, + variables: { + userId: '2', + }, + }, + result: { + data: { + messageSentToGroupChat: { + _id: '668ec1f1df364e03ac47a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + replyTo: null, + type: 'STRING', + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, + { + request: { + query: MESSAGE_SENT_TO_CHAT, + variables: { + userId: '1', + }, + }, + result: { + data: { + messageSentToGroupChat: { + _id: '668ec1f13603ac4697a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + replyTo: null, + type: 'STRING', + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, +]; + +const CHAT_BY_ID_QUERY_MOCK = [ + { + request: { + query: CHAT_BY_ID, + variables: { + id: '1', + }, + }, + result: { + data: { + chatById: { + _id: '1', + createdAt: '2345678903456', + isGroup: false, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: null, + name: '', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + type: 'STRING', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + ], + }, + }, + }, + }, + { + request: { + query: CHAT_BY_ID, + variables: { + id: '1', + }, + }, + result: { + data: { + chatById: { + _id: '1', + isGroup: false, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: null, + name: '', + createdAt: '2345678903456', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + type: 'STRING', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + ], + }, + }, + }, + }, + { + request: { + query: CHAT_BY_ID, + variables: { + id: '', + }, + }, + result: { + data: { + chatById: { + _id: '1', + isGroup: false, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: null, + name: '', + createdAt: '2345678903456', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + type: 'STRING', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + ], + }, + }, + }, + }, +]; + +const CHATS_LIST_MOCK = [ + { + request: { + query: CHATS_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844efc814dd40fgh03db811c4', + isGroup: true, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: { + _id: 'pw3ertyuiophgfre45678', + name: 'rtyu', + }, + createdAt: '2345678903456', + name: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + type: 'STRING', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + { + _id: '3', + firstName: 'Test', + lastName: 'User1', + email: 'test1@example.com', + image: '', + }, + { + _id: '4', + firstName: 'Test', + lastName: 'User2', + email: 'test2@example.com', + image: '', + }, + { + _id: '5', + firstName: 'Test', + lastName: 'User4', + email: 'test4@example.com', + image: '', + }, + ], + }, + { + _id: '65844efc814ddgh4003db811c4', + isGroup: true, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: { + _id: 'pw3ertyuiophgfre45678', + name: 'rtyu', + }, + createdAt: '2345678903456', + name: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + type: 'STRING', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + { + _id: '3', + firstName: 'Test', + lastName: 'User1', + email: 'test1@example.com', + image: '', + }, + { + _id: '4', + firstName: 'Test', + lastName: 'User2', + email: 'test2@example.com', + image: '', + }, + { + _id: '5', + firstName: 'Test', + lastName: 'User4', + email: 'test4@example.com', + image: '', + }, + ], + }, + ], + }, + }, + }, + { + request: { + query: CHATS_LIST, + variables: { + id: '', + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844ghjefc814dd4003db811c4', + isGroup: true, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: { + _id: 'pw3ertyuiophgfre45678', + name: 'rtyu', + }, + createdAt: '2345678903456', + name: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + type: 'STRING', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + { + _id: '3', + firstName: 'Test', + lastName: 'User1', + email: 'test1@example.com', + image: '', + }, + { + _id: '4', + firstName: 'Test', + lastName: 'User2', + email: 'test2@example.com', + image: '', + }, + { + _id: '5', + firstName: 'Test', + lastName: 'User4', + email: 'test4@example.com', + image: '', + }, + ], + }, + { + _id: 'ujhgtrdtyuiop', + isGroup: true, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: { + _id: 'pw3ertyuiophgfre45678', + name: 'rtyu', + }, + createdAt: '2345678903456', + name: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + type: 'STRING', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + { + _id: '3', + firstName: 'Test', + lastName: 'User1', + email: 'test1@example.com', + image: '', + }, + { + _id: '4', + firstName: 'Test', + lastName: 'User2', + email: 'test2@example.com', + image: '', + }, + { + _id: '5', + firstName: 'Test', + lastName: 'User4', + email: 'test4@example.com', + image: '', + }, + ], + }, + ], + }, + }, + }, + { + request: { + query: CHATS_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844efc814dhjmkdftyd4003db811c4', + isGroup: true, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: { + _id: 'pw3ertyuiophgfre45678', + name: 'rtyu', + }, + createdAt: '2345678903456', + name: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + type: 'STRING', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + { + _id: '3', + firstName: 'Test', + lastName: 'User1', + email: 'test1@example.com', + image: '', + }, + { + _id: '4', + firstName: 'Test', + lastName: 'User2', + email: 'test2@example.com', + image: '', + }, + { + _id: '5', + firstName: 'Test', + lastName: 'User4', + email: 'test4@example.com', + image: '', + }, + ], + }, + { + _id: '65844ewsedrffc814dd4003db811c4', + isGroup: true, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: { + _id: 'pw3ertyuiophgfre45678', + name: 'rtyu', + }, + createdAt: '2345678903456', + name: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + type: 'STRING', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + { + _id: '3', + firstName: 'Test', + lastName: 'User1', + email: 'test1@example.com', + image: '', + }, + { + _id: '4', + firstName: 'Test', + lastName: 'User2', + email: 'test2@example.com', + image: '', + }, + { + _id: '5', + firstName: 'Test', + lastName: 'User4', + email: 'test4@example.com', + image: '', + }, + ], + }, + ], + }, + }, + }, + { + request: { + query: CHATS_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844efc814dhjmkdftyd4003db811c4', + isGroup: true, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: { + _id: 'pw3ertyuiophgfre45678', + name: 'rtyu', + }, + createdAt: '2345678903456', + name: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + type: 'STRING', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + { + _id: '3', + firstName: 'Test', + lastName: 'User1', + email: 'test1@example.com', + image: '', + }, + { + _id: '4', + firstName: 'Test', + lastName: 'User2', + email: 'test2@example.com', + image: '', + }, + { + _id: '5', + firstName: 'Test', + lastName: 'User4', + email: 'test4@example.com', + image: '', + }, + ], + }, + { + _id: '65844ewsedrffc814dd4003db811c4', + isGroup: true, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: { + _id: 'pw3ertyuiophgfre45678', + name: 'rtyu', + }, + createdAt: '2345678903456', + name: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + type: 'STRING', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + { + _id: '3', + firstName: 'Test', + lastName: 'User1', + email: 'test1@example.com', + image: '', + }, + { + _id: '4', + firstName: 'Test', + lastName: 'User2', + email: 'test2@example.com', + image: '', + }, + { + _id: '5', + firstName: 'Test', + lastName: 'User4', + email: 'test4@example.com', + image: '', + }, + ], + }, + ], + }, + }, + }, +]; + +const GROUP_CHAT_BY_ID_QUERY_MOCK = [ + { + request: { + query: CHAT_BY_ID, + variables: { + id: '', + }, + }, + result: { + data: { + chatById: { + _id: '65844efc814dd4003db811c4', + isGroup: true, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: { + _id: 'pw3ertyuiophgfre45678', + name: 'rtyu', + }, + createdAt: '2345678903456', + name: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + type: 'STRING', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + { + _id: '3', + firstName: 'Test', + lastName: 'User1', + email: 'test1@example.com', + image: '', + }, + { + _id: '4', + firstName: 'Test', + lastName: 'User2', + email: 'test2@example.com', + image: '', + }, + { + _id: '5', + firstName: 'Test', + lastName: 'User4', + email: 'test4@example.com', + image: '', + }, + ], + }, + }, + }, + }, +]; + +const CREATE_CHAT_MUTATION_MOCK = [ + { + request: { + query: CREATE_CHAT, + variables: { + organizationId: undefined, + userIds: ['1', '6589389d2caa9d8d69087487'], + isGroup: false, + }, + }, + result: { + data: { + createChat: { + _id: '1', + createdAt: '2345678903456', + isGroup: false, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: null, + name: '', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + type: 'STRING', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + ], + }, + }, + }, + }, +]; + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +describe('Testing Create Direct Chat Modal [User Portal]', () => { + window.HTMLElement.prototype.scrollIntoView = jest.fn(); + + Object.defineProperty(window, 'matchMedia', { + writable: true, + value: jest.fn().mockImplementation((query) => ({ + matches: false, + media: query, + onchange: null, + addListener: jest.fn(), // Deprecated + removeListener: jest.fn(), // Deprecated + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn(), + })), + }); + + test('Open and close create new direct chat modal', async () => { + const mock = [ + ...GROUP_CHAT_BY_ID_QUERY_MOCK, + ...MESSAGE_SENT_TO_CHAT_MOCK, + ...UserConnectionListMock, + ...CHATS_LIST_MOCK, + ...CHAT_BY_ID_QUERY_MOCK, + ...CREATE_CHAT_MUTATION_MOCK, + ]; + render( + + + + + + + + + , + ); + + await wait(); + + const dropdown = await screen.findByTestId('dropdown'); + expect(dropdown).toBeInTheDocument(); + fireEvent.click(dropdown); + const newDirectChatBtn = await screen.findByTestId('newDirectChat'); + expect(newDirectChatBtn).toBeInTheDocument(); + fireEvent.click(newDirectChatBtn); + + const submitBtn = await screen.findByTestId('submitBtn'); + expect(submitBtn).toBeInTheDocument(); + + const searchInput = (await screen.findByTestId( + 'searchUser', + )) as HTMLInputElement; + expect(searchInput).toBeInTheDocument(); + + fireEvent.change(searchInput, { target: { value: 'Disha' } }); + + expect(searchInput.value).toBe('Disha'); + + fireEvent.click(submitBtn); + + const closeButton = screen.getByRole('button', { name: /close/i }); + expect(closeButton).toBeInTheDocument(); + + fireEvent.click(closeButton); + }); + + test('create new direct chat', async () => { + setItem('userId', '1'); + const mock = [ + ...GROUP_CHAT_BY_ID_QUERY_MOCK, + ...MESSAGE_SENT_TO_CHAT_MOCK, + ...UserConnectionListMock, + ...CHATS_LIST_MOCK, + ...CHAT_BY_ID_QUERY_MOCK, + ...CREATE_CHAT_MUTATION_MOCK, + ]; + render( + + + + + + + + + , + ); + + await wait(); + + const dropdown = await screen.findByTestId('dropdown'); + expect(dropdown).toBeInTheDocument(); + fireEvent.click(dropdown); + const newDirectChatBtn = await screen.findByTestId('newDirectChat'); + expect(newDirectChatBtn).toBeInTheDocument(); + fireEvent.click(newDirectChatBtn); + + const addBtn = await screen.findAllByTestId('addBtn'); + waitFor(() => { + expect(addBtn[0]).toBeInTheDocument(); + }); + + fireEvent.click(addBtn[0]); + + const closeButton = screen.getByRole('button', { name: /close/i }); + expect(closeButton).toBeInTheDocument(); + + fireEvent.click(closeButton); + + await new Promise(process.nextTick); + + await wait(); + }); +}); diff --git a/src/components/UserPortal/CreateDirectChat/CreateDirectChat.tsx b/src/components/UserPortal/CreateDirectChat/CreateDirectChat.tsx new file mode 100644 index 0000000000..e0ee9613c3 --- /dev/null +++ b/src/components/UserPortal/CreateDirectChat/CreateDirectChat.tsx @@ -0,0 +1,213 @@ +import { Paper, TableBody } from '@mui/material'; +import React, { useState } from 'react'; +import { Button, Form, Modal } from 'react-bootstrap'; +import styles from './CreateDirectChat.module.css'; +import type { ApolloQueryResult } from '@apollo/client'; +import { useMutation, useQuery } from '@apollo/client'; +import useLocalStorage from 'utils/useLocalstorage'; +import { + CREATE_CHAT, + CREATE_DIRECT_CHAT, +} from 'GraphQl/Mutations/OrganizationMutations'; +import Table from '@mui/material/Table'; +import TableCell, { tableCellClasses } from '@mui/material/TableCell'; +import TableContainer from '@mui/material/TableContainer'; +import TableHead from '@mui/material/TableHead'; +import TableRow from '@mui/material/TableRow'; +import { styled } from '@mui/material/styles'; +import type { InterfaceQueryUserListItem } from 'utils/interfaces'; +import { USERS_CONNECTION_LIST } from 'GraphQl/Queries/Queries'; +import Loader from 'components/Loader/Loader'; +import { Search } from '@mui/icons-material'; +import { useTranslation } from 'react-i18next'; +import { useParams } from 'react-router-dom'; + +interface InterfaceCreateDirectChatProps { + toggleCreateDirectChatModal: () => void; + createDirectChatModalisOpen: boolean; + chatsListRefetch: ( + variables?: + | Partial<{ + id: any; + }> + | undefined, + ) => Promise>; +} + +/** + * Styled table cell with custom styles. + */ + +const StyledTableCell = styled(TableCell)(({ theme }) => ({ + [`&.${tableCellClasses.head}`]: { + backgroundColor: ['#31bb6b', '!important'], + color: theme.palette.common.white, + }, + [`&.${tableCellClasses.body}`]: { + fontSize: 14, + }, +})); + +/** + * Styled table row with custom styles. + */ + +const StyledTableRow = styled(TableRow)(() => ({ + '&:last-child td, &:last-child th': { + border: 0, + }, +})); + +const { getItem } = useLocalStorage(); + +export default function createDirectChatModal({ + toggleCreateDirectChatModal, + createDirectChatModalisOpen, + chatsListRefetch, +}: InterfaceCreateDirectChatProps): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'userChat', + }); + + const { orgId: organizationId } = useParams(); + + const userId: string | null = getItem('userId'); + + const [userName, setUserName] = useState(''); + + const [createChat] = useMutation(CREATE_CHAT); + + const handleCreateDirectChat = async (id: string): Promise => { + await createChat({ + variables: { + organizationId, + userIds: [userId, id], + isGroup: false, + }, + }); + await chatsListRefetch(); + toggleCreateDirectChatModal(); + }; + + const { + data: allUsersData, + loading: allUsersLoading, + refetch: allUsersRefetch, + } = useQuery(USERS_CONNECTION_LIST, { + variables: { + firstName_contains: '', + lastName_contains: '', + }, + }); + + const handleUserModalSearchChange = (e: React.FormEvent): void => { + e.preventDefault(); + /* istanbul ignore next */ + const [firstName, lastName] = userName.split(' '); + + const newFilterData = { + firstName_contains: firstName || '', + lastName_contains: lastName || '', + }; + + allUsersRefetch({ + ...newFilterData, + }); + }; + + return ( + <> + + + {'Chat'} + + + {allUsersLoading ? ( + <> + + + ) : ( + <> +
    +
    + { + const { value } = e.target; + setUserName(value); + }} + /> + + +
    + + + + + # + {'user'} + {'Chat'} + + + + {allUsersData && + allUsersData.users.length > 0 && + allUsersData.users.map( + ( + userDetails: InterfaceQueryUserListItem, + index: number, + ) => ( + + + {index + 1} + + + {userDetails.user.firstName + + ' ' + + userDetails.user.lastName} +
    + {userDetails.user.email} +
    + + + +
    + ), + )} +
    +
    +
    + + )} +
    +
    + + ); +} diff --git a/src/components/UserPortal/CreateGroupChat/CreateGroupChat.module.css b/src/components/UserPortal/CreateGroupChat/CreateGroupChat.module.css new file mode 100644 index 0000000000..3795e402fa --- /dev/null +++ b/src/components/UserPortal/CreateGroupChat/CreateGroupChat.module.css @@ -0,0 +1,9 @@ +.userData { + height: 400px; + overflow-y: scroll; + overflow-x: hidden !important; +} + +.modalContent { + width: 530px; +} diff --git a/src/components/UserPortal/CreateGroupChat/CreateGroupChat.test.tsx b/src/components/UserPortal/CreateGroupChat/CreateGroupChat.test.tsx new file mode 100644 index 0000000000..7eeaeacac1 --- /dev/null +++ b/src/components/UserPortal/CreateGroupChat/CreateGroupChat.test.tsx @@ -0,0 +1,2455 @@ +import React from 'react'; +import { + act, + fireEvent, + render, + screen, + waitFor, + within, +} from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import { I18nextProvider } from 'react-i18next'; + +import { + USERS_CONNECTION_LIST, + USER_JOINED_ORGANIZATIONS, +} from 'GraphQl/Queries/Queries'; +import { BrowserRouter } from 'react-router-dom'; +import { Provider } from 'react-redux'; +import { store } from 'state/store'; +import i18nForTest from 'utils/i18nForTest'; +import Chat from '../../../screens/UserPortal/Chat/Chat'; +import { + CREATE_CHAT, + MESSAGE_SENT_TO_CHAT, +} from 'GraphQl/Mutations/OrganizationMutations'; +import { CHATS_LIST, CHAT_BY_ID } from 'GraphQl/Queries/PlugInQueries'; +import useLocalStorage from 'utils/useLocalstorage'; +import userEvent from '@testing-library/user-event'; + +const { setItem } = useLocalStorage(); + +const USER_JOINED_ORG_MOCK = [ + { + request: { + query: USER_JOINED_ORGANIZATIONS, + variables: { + id: '1', + }, + }, + result: { + data: { + users: [ + { + user: { + joinedOrganizations: [ + { + __typename: 'Organization', + _id: '6401ff65ce8e8406b8f07af2', + name: 'Test Org 1', + image: '', + description: 'New Desc', + address: { + city: 'abc', + countryCode: '123', + postalCode: '456', + state: 'def', + dependentLocality: 'ghi', + line1: 'asdfg', + line2: 'dfghj', + sortingCode: '4567', + }, + createdAt: '1234567890', + userRegistrationRequired: true, + creator: { + __typename: 'User', + firstName: 'John', + lastName: 'Doe', + }, + members: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + admins: [ + { + _id: '45gj5678jk45678fvgbhnr4rtgh', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + membershipRequests: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + }, + { + __typename: 'Organization', + _id: '6401ff65ce8e8406b8f07af2', + name: 'Test Org 1', + image: '', + description: 'New Desc', + address: { + city: 'abc', + countryCode: '123', + postalCode: '456', + state: 'def', + dependentLocality: 'ghi', + line1: 'asdfg', + line2: 'dfghj', + sortingCode: '4567', + }, + createdAt: '1234567890', + userRegistrationRequired: true, + creator: { + __typename: 'User', + firstName: 'John', + lastName: 'Doe', + }, + members: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + admins: [ + { + _id: '45gj5678jk45678fvgbhnr4rtgh', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + membershipRequests: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + }, + { + __typename: 'Organization', + _id: '6401ff65ce8e8406b8f07af2', + name: 'Test Org 1', + image: '', + description: 'New Desc', + address: { + city: 'abc', + countryCode: '123', + postalCode: '456', + state: 'def', + dependentLocality: 'ghi', + line1: 'asdfg', + line2: 'dfghj', + sortingCode: '4567', + }, + createdAt: '1234567890', + userRegistrationRequired: true, + creator: { + __typename: 'User', + firstName: 'John', + lastName: 'Doe', + }, + members: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + admins: [ + { + _id: '45gj5678jk45678fvgbhnr4rtgh', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + membershipRequests: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + }, + { + __typename: 'Organization', + _id: '6401ff65ce8e8406b8f07af2', + name: 'Test Org 1', + image: '', + description: 'New Desc', + address: { + city: 'abc', + countryCode: '123', + postalCode: '456', + state: 'def', + dependentLocality: 'ghi', + line1: 'asdfg', + line2: 'dfghj', + sortingCode: '4567', + }, + createdAt: '1234567890', + userRegistrationRequired: true, + creator: { + __typename: 'User', + firstName: 'John', + lastName: 'Doe', + }, + members: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + admins: [ + { + _id: '45gj5678jk45678fvgbhnr4rtgh', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + membershipRequests: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + }, + ], + }, + }, + ], + }, + }, + }, + { + request: { + query: USER_JOINED_ORGANIZATIONS, + variables: { + id: '1', + }, + }, + result: { + data: { + users: [ + { + user: { + joinedOrganizations: [ + { + __typename: 'Organization', + _id: '6401ff65ce8e8406b8f07af2', + name: 'Test org', + image: '', + description: 'New Desc', + address: { + city: 'abc', + countryCode: '123', + postalCode: '456', + state: 'def', + dependentLocality: 'ghi', + line1: 'asdfg', + line2: 'dfghj', + sortingCode: '4567', + }, + createdAt: '1234567890', + userRegistrationRequired: true, + creator: { + __typename: 'User', + firstName: 'John', + lastName: 'Doe', + }, + members: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + admins: [ + { + _id: '45gj5678jk45678fvgbhnr4rtgh', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + membershipRequests: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + }, + { + __typename: 'Organization', + _id: 'qsxhgjhbmnbkhlk,njgjfhgv', + name: 'Any Organization', + image: '', + description: 'New Desc', + address: { + city: 'abc', + countryCode: '123', + postalCode: '456', + state: 'def', + dependentLocality: 'ghi', + line1: 'asdfg', + line2: 'dfghj', + sortingCode: '4567', + }, + createdAt: '1234567890', + userRegistrationRequired: true, + creator: { + __typename: 'User', + firstName: 'John', + lastName: 'Doe', + }, + members: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + admins: [ + { + _id: '45gj5678jk45678fvgbhnr4rtgh', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + membershipRequests: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + }, + ], + }, + }, + ], + }, + }, + }, + { + request: { + query: USER_JOINED_ORGANIZATIONS, + variables: { + id: '1', + }, + }, + result: { + data: { + users: [ + { + user: { + joinedOrganizations: [ + { + __typename: 'Organization', + _id: '6401ff65ce8e8406b8fhgjhnm07af2', + name: 'Test org', + image: '', + description: 'New Desc', + address: { + city: 'abc', + countryCode: '123', + postalCode: '456', + state: 'def', + dependentLocality: 'ghi', + line1: 'asdfg', + line2: 'dfghj', + sortingCode: '4567', + }, + createdAt: '1234567890', + userRegistrationRequired: true, + creator: { + __typename: 'User', + firstName: 'John', + lastName: 'Doe', + }, + members: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + admins: [ + { + _id: '45gj5678jk45678fvgbhnr4rtgh', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + membershipRequests: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + }, + { + __typename: 'Organization', + _id: '6401ff65ce8egfhbn8406b8f07af2', + name: 'Any Organization', + image: '', + description: 'New Desc', + address: { + city: 'abc', + countryCode: '123', + postalCode: '456', + state: 'def', + dependentLocality: 'ghi', + line1: 'asdfg', + line2: 'dfghj', + sortingCode: '4567', + }, + createdAt: '1234567890', + userRegistrationRequired: true, + creator: { + __typename: 'User', + firstName: 'John', + lastName: 'Doe', + }, + members: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + admins: [ + { + _id: '45gj5678jk45678fvgbhnr4rtgh', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + membershipRequests: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + }, + ], + }, + }, + ], + }, + }, + }, + { + request: { + query: USER_JOINED_ORGANIZATIONS, + variables: { + id: null, + }, + }, + result: { + data: { + users: [ + { + user: { + joinedOrganizations: [ + { + __typename: 'Organization', + _id: '6401ff65fghce8e8406b8f07af2', + name: 'Test org', + image: '', + description: 'New Desc', + address: { + city: 'abc', + countryCode: '123', + postalCode: '456', + state: 'def', + dependentLocality: 'ghi', + line1: 'asdfg', + line2: 'dfghj', + sortingCode: '4567', + }, + createdAt: '1234567890', + userRegistrationRequired: true, + creator: { + __typename: 'User', + firstName: 'John', + lastName: 'Doe', + }, + members: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + admins: [ + { + _id: '45gj5678jk45678fvgbhnr4rtgh', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + membershipRequests: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + }, + { + __typename: 'Organization', + _id: '6401ff65ce8e8406b8jygjgf07af2', + name: 'Any Organization', + image: '', + description: 'New Desc', + address: { + city: 'abc', + countryCode: '123', + postalCode: '456', + state: 'def', + dependentLocality: 'ghi', + line1: 'asdfg', + line2: 'dfghj', + sortingCode: '4567', + }, + createdAt: '1234567890', + userRegistrationRequired: true, + creator: { + __typename: 'User', + firstName: 'John', + lastName: 'Doe', + }, + members: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + admins: [ + { + _id: '45gj5678jk45678fvgbhnr4rtgh', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + membershipRequests: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + }, + ], + }, + }, + ], + }, + }, + }, + { + request: { + query: USER_JOINED_ORGANIZATIONS, + variables: { + id: null, + }, + }, + result: { + data: { + users: [ + { + user: { + joinedOrganizations: [ + { + __typename: 'Organization', + _id: '6401ff65cehgh8e8406b8f07af2', + name: 'Test org', + image: '', + description: 'New Desc', + address: { + city: 'abc', + countryCode: '123', + postalCode: '456', + state: 'def', + dependentLocality: 'ghi', + line1: 'asdfg', + line2: 'dfghj', + sortingCode: '4567', + }, + createdAt: '1234567890', + userRegistrationRequired: true, + creator: { + __typename: 'User', + firstName: 'John', + lastName: 'Doe', + }, + members: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + admins: [ + { + _id: '45gj5678jk45678fvgbhnr4rtgh', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + membershipRequests: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + }, + { + __typename: 'Organization', + _id: '6401ff65ce8e8406b8f07af2', + name: 'Any Organization', + image: '', + description: 'New Desc', + address: { + city: 'abc', + countryCode: '123', + postalCode: '456', + state: 'def', + dependentLocality: 'ghi', + line1: 'asdfg', + line2: 'dfghj', + sortingCode: '4567', + }, + createdAt: '1234567890', + userRegistrationRequired: true, + creator: { + __typename: 'User', + firstName: 'John', + lastName: 'Doe', + }, + members: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + admins: [ + { + _id: '45gj5678jk45678fvgbhnr4rtgh', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + membershipRequests: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + }, + ], + }, + }, + ], + }, + }, + }, + { + request: { + query: USER_JOINED_ORGANIZATIONS, + variables: { + id: null, + }, + }, + result: { + data: { + users: [ + { + user: { + joinedOrganizations: [ + { + __typename: 'Organization', + _id: '6401ff65ce8e8406nbmnmb8f07af2', + name: 'Test org', + image: '', + description: 'New Desc', + address: { + city: 'abc', + countryCode: '123', + postalCode: '456', + state: 'def', + dependentLocality: 'ghi', + line1: 'asdfg', + line2: 'dfghj', + sortingCode: '4567', + }, + createdAt: '1234567890', + userRegistrationRequired: true, + creator: { + __typename: 'User', + firstName: 'John', + lastName: 'Doe', + }, + members: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + admins: [ + { + _id: '45gj5678jk45678fvgbhnr4rtgh', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + membershipRequests: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + }, + { + __typename: 'Organization', + _id: '6401ff65ce8e8406b8fnnmm07af2', + name: 'Any Organization', + image: '', + description: 'New Desc', + address: { + city: 'abc', + countryCode: '123', + postalCode: '456', + state: 'def', + dependentLocality: 'ghi', + line1: 'asdfg', + line2: 'dfghj', + sortingCode: '4567', + }, + createdAt: '1234567890', + userRegistrationRequired: true, + creator: { + __typename: 'User', + firstName: 'John', + lastName: 'Doe', + }, + members: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + admins: [ + { + _id: '45gj5678jk45678fvgbhnr4rtgh', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + membershipRequests: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + }, + ], + }, + }, + ], + }, + }, + }, +]; + +const UserConnectionListMock = [ + { + request: { + query: USERS_CONNECTION_LIST, + variables: { + firstName_contains: '', + lastName_contains: '', + }, + }, + result: { + data: { + users: [ + { + user: { + firstName: 'Deanne', + lastName: 'Marks', + image: null, + _id: '6589389d2caa9d8d69087487', + email: 'testuser8@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + organizationsBlockedBy: [], + joinedOrganizations: [ + { + _id: '6537904485008f171cf29924', + name: 'Unity Foundation', + image: null, + address: { + city: 'Queens', + countryCode: 'US', + dependentLocality: 'Some Dependent Locality', + line1: '123 Coffee Street', + line2: 'Apartment 501', + postalCode: '11427', + sortingCode: 'ABC-133', + state: 'NYC', + __typename: 'Address', + }, + createdAt: '2023-04-13T05:16:52.827Z', + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + __typename: 'Organization', + }, + { + _id: '6637904485008f171cf29924', + name: 'Unity Foundation', + image: null, + address: { + city: 'Staten Island', + countryCode: 'US', + dependentLocality: 'Some Dependent Locality', + line1: '123 church Street', + line2: 'Apartment 499', + postalCode: '10301', + sortingCode: 'ABC-122', + state: 'NYC', + __typename: 'Address', + }, + createdAt: '2023-04-13T05:16:52.827Z', + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + __typename: 'Organization', + }, + { + _id: '6737904485008f171cf29924', + name: 'Unity Foundation', + image: null, + address: { + city: 'Brooklyn', + countryCode: 'US', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Main Street', + line2: 'Apt 456', + postalCode: '10004', + sortingCode: 'ABC-789', + state: 'NY', + __typename: 'Address', + }, + createdAt: '2023-04-13T05:16:52.827Z', + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + __typename: 'Organization', + }, + { + _id: '6437904485008f171cf29924', + name: 'Unity Foundation', + image: null, + address: { + city: 'Bronx', + countryCode: 'US', + dependentLocality: 'Some Dependent Locality', + line1: '123 Random Street', + line2: 'Apartment 456', + postalCode: '10451', + sortingCode: 'ABC-123', + state: 'NYC', + __typename: 'Address', + }, + createdAt: '2023-04-13T05:16:52.827Z', + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + __typename: 'Organization', + }, + ], + __typename: 'User', + }, + appUserProfile: { + _id: '64378abd85308f171cf2993d', + adminFor: [], + isSuperAdmin: false, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + __typename: 'AppUserProfile', + }, + __typename: 'UserData', + }, + ], + }, + }, + }, + { + request: { + query: USERS_CONNECTION_LIST, + variables: { + firstName_contains: '', + lastName_contains: '', + }, + }, + result: { + data: { + users: { + user: [ + { + firstName: 'Disha', + lastName: 'Talreja', + image: 'img', + _id: '1', + email: 'disha@email.com', + createdAt: '', + appUserProfile: { + _id: '12', + isSuperAdmin: 'false', + createdOrganizations: { + _id: '345678', + }, + createdEvents: { + _id: '34567890', + }, + }, + organizationsBlockedBy: [], + joinedOrganizations: [], + }, + { + firstName: 'Disha', + lastName: 'Talreja', + image: 'img', + _id: '1', + email: 'disha@email.com', + createdAt: '', + appUserProfile: { + _id: '12', + isSuperAdmin: 'false', + createdOrganizations: { + _id: '345678', + }, + createdEvents: { + _id: '34567890', + }, + }, + organizationsBlockedBy: [], + joinedOrganizations: [], + }, + { + firstName: 'Disha', + lastName: 'Talreja', + image: 'img', + _id: '1', + email: 'disha@email.com', + createdAt: '', + appUserProfile: { + _id: '12', + isSuperAdmin: 'false', + createdOrganizations: { + _id: '345678', + }, + createdEvents: { + _id: '34567890', + }, + }, + organizationsBlockedBy: [], + joinedOrganizations: [], + }, + ], + }, + }, + }, + }, + { + request: { + query: USERS_CONNECTION_LIST, + variables: { + firstName_contains: 'Disha', + lastName_contains: '', + }, + }, + result: { + data: { + users: [ + { + user: { + firstName: 'Deanne', + lastName: 'Marks', + image: null, + _id: '6589389d2caa9d8d69087487', + email: 'testuser8@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + organizationsBlockedBy: [], + joinedOrganizations: [ + { + _id: '6537904485008f171cf29924', + name: 'Unity Foundation', + image: null, + address: { + city: 'Queens', + countryCode: 'US', + dependentLocality: 'Some Dependent Locality', + line1: '123 Coffee Street', + line2: 'Apartment 501', + postalCode: '11427', + sortingCode: 'ABC-133', + state: 'NYC', + __typename: 'Address', + }, + createdAt: '2023-04-13T05:16:52.827Z', + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + __typename: 'Organization', + }, + { + _id: '6637904485008f171cf29924', + name: 'Unity Foundation', + image: null, + address: { + city: 'Staten Island', + countryCode: 'US', + dependentLocality: 'Some Dependent Locality', + line1: '123 church Street', + line2: 'Apartment 499', + postalCode: '10301', + sortingCode: 'ABC-122', + state: 'NYC', + __typename: 'Address', + }, + createdAt: '2023-04-13T05:16:52.827Z', + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + __typename: 'Organization', + }, + { + _id: '6737904485008f171cf29924', + name: 'Unity Foundation', + image: null, + address: { + city: 'Brooklyn', + countryCode: 'US', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Main Street', + line2: 'Apt 456', + postalCode: '10004', + sortingCode: 'ABC-789', + state: 'NY', + __typename: 'Address', + }, + createdAt: '2023-04-13T05:16:52.827Z', + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + __typename: 'Organization', + }, + { + _id: '6437904485008f171cf29924', + name: 'Unity Foundation', + image: null, + address: { + city: 'Bronx', + countryCode: 'US', + dependentLocality: 'Some Dependent Locality', + line1: '123 Random Street', + line2: 'Apartment 456', + postalCode: '10451', + sortingCode: 'ABC-123', + state: 'NYC', + __typename: 'Address', + }, + createdAt: '2023-04-13T05:16:52.827Z', + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + __typename: 'Organization', + }, + ], + __typename: 'User', + }, + appUserProfile: { + _id: '64378abd85308f171cf2993d', + adminFor: [], + isSuperAdmin: false, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + __typename: 'AppUserProfile', + }, + __typename: 'UserData', + }, + ], + }, + }, + }, +]; + +const MESSAGE_SENT_TO_CHAT_MOCK = [ + { + request: { + query: MESSAGE_SENT_TO_CHAT, + variables: { + userId: null, + }, + }, + result: { + data: { + messageSentToChat: { + _id: '668ec1f1364e03ac47a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + type: 'STRING', + replyTo: null, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, + { + request: { + query: MESSAGE_SENT_TO_CHAT, + variables: { + userId: '2', + }, + }, + result: { + data: { + messageSentToGroupChat: { + _id: '668ec1f1df364e03ac47a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + replyTo: null, + type: 'STRING', + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, + { + request: { + query: MESSAGE_SENT_TO_CHAT, + variables: { + userId: '1', + }, + }, + result: { + data: { + messageSentToGroupChat: { + _id: '668ec1f13603ac4697a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + replyTo: null, + type: 'STRING', + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, +]; + +const CHAT_BY_ID_QUERY_MOCK = [ + { + request: { + query: CHAT_BY_ID, + variables: { + id: '1', + }, + }, + result: { + data: { + chatById: { + _id: '1', + createdAt: '2345678903456', + isGroup: false, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: null, + name: '', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + type: 'STRING', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + ], + }, + }, + }, + }, + { + request: { + query: CHAT_BY_ID, + variables: { + id: '1', + }, + }, + result: { + data: { + chatById: { + _id: '1', + isGroup: false, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: null, + name: '', + createdAt: '2345678903456', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + type: 'STRING', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + ], + }, + }, + }, + }, + { + request: { + query: CHAT_BY_ID, + variables: { + id: '', + }, + }, + result: { + data: { + chatById: { + _id: '1', + isGroup: false, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: null, + name: '', + createdAt: '2345678903456', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + type: 'STRING', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + ], + }, + }, + }, + }, +]; + +const CHATS_LIST_MOCK = [ + { + request: { + query: CHATS_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844efc814dd40fgh03db811c4', + isGroup: true, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: { + _id: 'pw3ertyuiophgfre45678', + name: 'rtyu', + }, + createdAt: '2345678903456', + name: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + type: 'STRING', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + { + _id: '3', + firstName: 'Test', + lastName: 'User1', + email: 'test1@example.com', + image: '', + }, + { + _id: '4', + firstName: 'Test', + lastName: 'User2', + email: 'test2@example.com', + image: '', + }, + { + _id: '5', + firstName: 'Test', + lastName: 'User4', + email: 'test4@example.com', + image: '', + }, + ], + }, + { + _id: '65844efc814ddgh4003db811c4', + isGroup: true, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: { + _id: 'pw3ertyuiophgfre45678', + name: 'rtyu', + }, + createdAt: '2345678903456', + name: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + type: 'STRING', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + { + _id: '3', + firstName: 'Test', + lastName: 'User1', + email: 'test1@example.com', + image: '', + }, + { + _id: '4', + firstName: 'Test', + lastName: 'User2', + email: 'test2@example.com', + image: '', + }, + { + _id: '5', + firstName: 'Test', + lastName: 'User4', + email: 'test4@example.com', + image: '', + }, + ], + }, + ], + }, + }, + }, + { + request: { + query: CHATS_LIST, + variables: { + id: '', + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844ghjefc814dd4003db811c4', + isGroup: true, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: { + _id: 'pw3ertyuiophgfre45678', + name: 'rtyu', + }, + createdAt: '2345678903456', + name: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + type: 'STRING', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + { + _id: '3', + firstName: 'Test', + lastName: 'User1', + email: 'test1@example.com', + image: '', + }, + { + _id: '4', + firstName: 'Test', + lastName: 'User2', + email: 'test2@example.com', + image: '', + }, + { + _id: '5', + firstName: 'Test', + lastName: 'User4', + email: 'test4@example.com', + image: '', + }, + ], + }, + { + _id: 'ujhgtrdtyuiop', + isGroup: true, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: { + _id: 'pw3ertyuiophgfre45678', + name: 'rtyu', + }, + createdAt: '2345678903456', + name: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + type: 'STRING', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + { + _id: '3', + firstName: 'Test', + lastName: 'User1', + email: 'test1@example.com', + image: '', + }, + { + _id: '4', + firstName: 'Test', + lastName: 'User2', + email: 'test2@example.com', + image: '', + }, + { + _id: '5', + firstName: 'Test', + lastName: 'User4', + email: 'test4@example.com', + image: '', + }, + ], + }, + ], + }, + }, + }, + { + request: { + query: CHATS_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844efc814dhjmkdftyd4003db811c4', + isGroup: true, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: { + _id: 'pw3ertyuiophgfre45678', + name: 'rtyu', + }, + createdAt: '2345678903456', + name: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + type: 'STRING', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + { + _id: '3', + firstName: 'Test', + lastName: 'User1', + email: 'test1@example.com', + image: '', + }, + { + _id: '4', + firstName: 'Test', + lastName: 'User2', + email: 'test2@example.com', + image: '', + }, + { + _id: '5', + firstName: 'Test', + lastName: 'User4', + email: 'test4@example.com', + image: '', + }, + ], + }, + { + _id: '65844ewsedrffc814dd4003db811c4', + isGroup: true, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: { + _id: 'pw3ertyuiophgfre45678', + name: 'rtyu', + }, + createdAt: '2345678903456', + name: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + type: 'STRING', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + { + _id: '3', + firstName: 'Test', + lastName: 'User1', + email: 'test1@example.com', + image: '', + }, + { + _id: '4', + firstName: 'Test', + lastName: 'User2', + email: 'test2@example.com', + image: '', + }, + { + _id: '5', + firstName: 'Test', + lastName: 'User4', + email: 'test4@example.com', + image: '', + }, + ], + }, + ], + }, + }, + }, +]; + +const GROUP_CHAT_BY_ID_QUERY_MOCK = [ + { + request: { + query: CHAT_BY_ID, + variables: { + id: '', + }, + }, + result: { + data: { + chatById: { + _id: '65844efc814dd4003db811c4', + isGroup: true, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: { + _id: 'pw3ertyuiophgfre45678', + name: 'rtyu', + }, + createdAt: '2345678903456', + name: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + type: 'STRING', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + { + _id: '3', + firstName: 'Test', + lastName: 'User1', + email: 'test1@example.com', + image: '', + }, + { + _id: '4', + firstName: 'Test', + lastName: 'User2', + email: 'test2@example.com', + image: '', + }, + { + _id: '5', + firstName: 'Test', + lastName: 'User4', + email: 'test4@example.com', + image: '', + }, + ], + }, + }, + }, + }, +]; + +const CREATE_CHAT_MUTATION = [ + { + request: { + query: CREATE_CHAT, + variables: { + organizationId: '6401ff65ce8e8406b8jygjgf07af2', + userIds: [null], + name: 'Test Group', + isGroup: true, + }, + }, + result: { + data: { + createChat: { + _id: '65844efc814dd4003db811c4', + isGroup: true, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: { + _id: 'pw3ertyuiophgfre45678', + name: 'rtyu', + }, + createdAt: '2345678903456', + name: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + type: 'STRING', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + { + _id: '3', + firstName: 'Test', + lastName: 'User1', + email: 'test1@example.com', + image: '', + }, + { + _id: '4', + firstName: 'Test', + lastName: 'User2', + email: 'test2@example.com', + image: '', + }, + { + _id: '5', + firstName: 'Test', + lastName: 'User4', + email: 'test4@example.com', + image: '', + }, + ], + }, + }, + }, + }, + { + request: { + query: CREATE_CHAT, + variables: { + organizationId: '', + userIds: [null], + name: 'Test Group', + isGroup: true, + }, + }, + result: { + data: { + createChat: { + _id: '65844efc814dd4003db811c4', + isGroup: true, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: { + _id: 'pw3ertyuiophgfre45678', + name: 'rtyu', + }, + createdAt: '2345678903456', + name: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + type: 'STRING', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + { + _id: '3', + firstName: 'Test', + lastName: 'User1', + email: 'test1@example.com', + image: '', + }, + { + _id: '4', + firstName: 'Test', + lastName: 'User2', + email: 'test2@example.com', + image: '', + }, + { + _id: '5', + firstName: 'Test', + lastName: 'User4', + email: 'test4@example.com', + image: '', + }, + ], + }, + }, + }, + }, +]; + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +describe('Testing Create Group Chat Modal [User Portal]', () => { + window.HTMLElement.prototype.scrollIntoView = jest.fn(); + + Object.defineProperty(window, 'matchMedia', { + writable: true, + value: jest.fn().mockImplementation((query) => ({ + matches: false, + media: query, + onchange: null, + addListener: jest.fn(), // Deprecated + removeListener: jest.fn(), // Deprecated + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn(), + })), + }); + + test('open and close create new direct chat modal', async () => { + const mock = [ + ...USER_JOINED_ORG_MOCK, + ...GROUP_CHAT_BY_ID_QUERY_MOCK, + ...MESSAGE_SENT_TO_CHAT_MOCK, + ...CHAT_BY_ID_QUERY_MOCK, + ...CHATS_LIST_MOCK, + ...UserConnectionListMock, + ...CREATE_CHAT_MUTATION, + ...CHATS_LIST_MOCK, + ]; + render( + + + + + + + + + , + ); + + await wait(); + + const dropdown = await screen.findByTestId('dropdown'); + expect(dropdown).toBeInTheDocument(); + fireEvent.click(dropdown); + const newGroupChatBtn = await screen.findByTestId('newGroupChat'); + expect(newGroupChatBtn).toBeInTheDocument(); + fireEvent.click(newGroupChatBtn); + + const closeButton = screen.getByRole('button', { name: /close/i }); + expect(closeButton).toBeInTheDocument(); + + fireEvent.click(closeButton); + }); + + test('create new group chat', async () => { + const mock = [ + ...USER_JOINED_ORG_MOCK, + ...GROUP_CHAT_BY_ID_QUERY_MOCK, + ...MESSAGE_SENT_TO_CHAT_MOCK, + ...CHAT_BY_ID_QUERY_MOCK, + ...CHATS_LIST_MOCK, + ...UserConnectionListMock, + ...CREATE_CHAT_MUTATION, + ...CHATS_LIST_MOCK, + ]; + render( + + + + + + + + + , + ); + + await wait(); + + const dropdown = await screen.findByTestId('dropdown'); + expect(dropdown).toBeInTheDocument(); + fireEvent.click(dropdown); + + const newGroupChatBtn = await screen.findByTestId('newGroupChat'); + expect(newGroupChatBtn).toBeInTheDocument(); + + fireEvent.click(newGroupChatBtn); + + await waitFor(async () => { + expect( + await screen.findByTestId('createGroupChatModal'), + ).toBeInTheDocument(); + }); + + const groupTitleInput = screen.getByLabelText( + 'Group name', + ) as HTMLInputElement; + + expect(groupTitleInput).toBeInTheDocument(); + + fireEvent.change(groupTitleInput, { target: { value: 'Test Group' } }); + await waitFor(() => { + expect(groupTitleInput.value).toBe('Test Group'); + }); + + const selectLabel = /select organization/i; + const orgSelect = await screen.findByLabelText('Select Organization'); + // console.log(prettyDOM(document)); + + // act(() => { + // fireEvent.change(orgSelect, { + // target: { value: '6401ff65ce8e8406b8f07af2' }, + // }); + // }) + // fireEvent.change(orgSelect, { + // target: { value: '6401ff65ce8e8406b8f07af2' }, + // }); + + // act(() => { + userEvent.click(orgSelect); + + const optionsPopupEl = await screen.findByRole('listbox', { + name: selectLabel, + }); + + userEvent.click(within(optionsPopupEl).getByText(/any organization/i)); + // }); + + // await waitFor(async () => { + // const option = await screen.findAllByText('Any Organization'); + + // console.log("option", option); + // }); + + const nextBtn = await screen.findByTestId('nextBtn'); + + act(() => { + fireEvent.click(nextBtn); + }); + + const createBtn = await screen.findByTestId('createBtn'); + await waitFor(async () => { + expect(createBtn).toBeInTheDocument(); + }); + + await act(async () => { + fireEvent.click(await screen.findByTestId('createBtn')); + }); + + // await waitFor(() => { + // expect(createBtn).not.toBeInTheDocument(); + // }); + }, 3000); + + test('add and remove user', async () => { + setItem('userId', '1'); + const mock = [ + ...USER_JOINED_ORG_MOCK, + ...GROUP_CHAT_BY_ID_QUERY_MOCK, + ...MESSAGE_SENT_TO_CHAT_MOCK, + ...CHAT_BY_ID_QUERY_MOCK, + ...CHATS_LIST_MOCK, + ...UserConnectionListMock, + ...CREATE_CHAT_MUTATION, + ...CHATS_LIST_MOCK, + ]; + render( + + + + + + + + + , + ); + + await wait(); + + const dropdown = await screen.findByTestId('dropdown'); + expect(dropdown).toBeInTheDocument(); + fireEvent.click(dropdown); + const newGroupChatBtn = await screen.findByTestId('newGroupChat'); + expect(newGroupChatBtn).toBeInTheDocument(); + fireEvent.click(newGroupChatBtn); + + await waitFor(async () => { + expect( + await screen.findByTestId('createGroupChatModal'), + ).toBeInTheDocument(); + }); + + const nextBtn = await screen.findByTestId('nextBtn'); + + act(() => { + fireEvent.click(nextBtn); + }); + + await waitFor(async () => { + const addBtn = await screen.findAllByTestId('addBtn'); + expect(addBtn[0]).toBeInTheDocument(); + }); + + const addBtn = await screen.findAllByTestId('addBtn'); + + fireEvent.click(addBtn[0]); + + const removeBtn = await screen.findAllByText('Remove'); + await waitFor(async () => { + expect(removeBtn[0]).toBeInTheDocument(); + }); + fireEvent.click(removeBtn[0]); + + await waitFor(() => { + expect(addBtn[0]).toBeInTheDocument(); + }); + + const submitBtn = await screen.findByTestId('submitBtn'); + + expect(submitBtn).toBeInTheDocument(); + + const searchInput = (await screen.findByTestId( + 'searchUser', + )) as HTMLInputElement; + expect(searchInput).toBeInTheDocument(); + + fireEvent.change(searchInput, { target: { value: 'Disha' } }); + + expect(searchInput.value).toBe('Disha'); + + fireEvent.click(submitBtn); + + const closeButton = screen.getAllByRole('button', { name: /close/i }); + expect(closeButton[0]).toBeInTheDocument(); + + fireEvent.click(closeButton[0]); + + await wait(500); + }); +}); diff --git a/src/components/UserPortal/CreateGroupChat/CreateGroupChat.tsx b/src/components/UserPortal/CreateGroupChat/CreateGroupChat.tsx new file mode 100644 index 0000000000..099a42310a --- /dev/null +++ b/src/components/UserPortal/CreateGroupChat/CreateGroupChat.tsx @@ -0,0 +1,394 @@ +import { + FormControl, + InputLabel, + MenuItem, + Paper, + Select, + TableBody, +} from '@mui/material'; +import type { SelectChangeEvent } from '@mui/material/Select'; +import React, { useEffect, useState } from 'react'; +import { Button, Form, Modal } from 'react-bootstrap'; +import styles from './CreateGroupChat.module.css'; +import type { ApolloQueryResult } from '@apollo/client'; +import { useMutation, useQuery } from '@apollo/client'; +import { USER_JOINED_ORGANIZATIONS } from 'GraphQl/Queries/OrganizationQueries'; +import useLocalStorage from 'utils/useLocalstorage'; +import { CREATE_CHAT } from 'GraphQl/Mutations/OrganizationMutations'; +import Table from '@mui/material/Table'; +import TableCell, { tableCellClasses } from '@mui/material/TableCell'; +import TableContainer from '@mui/material/TableContainer'; +import TableHead from '@mui/material/TableHead'; +import TableRow from '@mui/material/TableRow'; +import { styled } from '@mui/material/styles'; +import type { InterfaceQueryUserListItem } from 'utils/interfaces'; +import { USERS_CONNECTION_LIST } from 'GraphQl/Queries/Queries'; +import Loader from 'components/Loader/Loader'; +import { Search } from '@mui/icons-material'; +import { useTranslation } from 'react-i18next'; + +interface InterfaceCreateGroupChatProps { + toggleCreateGroupChatModal: () => void; + createGroupChatModalisOpen: boolean; + chatsListRefetch: ( + variables?: + | Partial<{ + id: string; + }> + | undefined, + ) => Promise>; +} + +interface InterfaceOrganization { + _id: string; + name: string; + image: string; + description: string; + admins: []; + members: []; + address: { + city: string; + countryCode: string; + line1: string; + postalCode: string; + state: string; + }; + membershipRequestStatus: string; + userRegistrationRequired: boolean; + membershipRequests: { + _id: string; + user: { + _id: string; + }; + }[]; +} + +/** + * Styled table cell with custom styles. + */ + +const StyledTableCell = styled(TableCell)(({ theme }) => ({ + [`&.${tableCellClasses.head}`]: { + backgroundColor: ['#31bb6b', '!important'], + color: theme.palette.common.white, + }, + [`&.${tableCellClasses.body}`]: { + fontSize: 14, + }, +})); + +/** + * Styled table row with custom styles. + */ + +const StyledTableRow = styled(TableRow)(() => ({ + '&:last-child td, &:last-child th': { + border: 0, + }, +})); + +const { getItem } = useLocalStorage(); + +export default function CreateGroupChat({ + toggleCreateGroupChatModal, + createGroupChatModalisOpen, + chatsListRefetch, +}: InterfaceCreateGroupChatProps): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'userChat', + }); + + const userId: string | null = getItem('userId'); + + const [createChat] = useMutation(CREATE_CHAT); + + const [organizations, setOrganizations] = useState([]); + const [selectedOrganization, setSelectedOrganization] = useState(''); + const [title, setTitle] = useState(''); + const [userIds, setUserIds] = useState([]); + + const [addUserModalisOpen, setAddUserModalisOpen] = useState(false); + + function openAddUserModal(): void { + setAddUserModalisOpen(true); + } + + const toggleAddUserModal = /* istanbul ignore next */ (): void => + setAddUserModalisOpen(!addUserModalisOpen); + + const handleChange = (event: SelectChangeEvent): void => { + setSelectedOrganization(event.target.value as string); + }; + + const { data: joinedOrganizationsData } = useQuery( + USER_JOINED_ORGANIZATIONS, + { + variables: { id: userId }, + }, + ); + + function reset(): void { + setTitle(''); + setUserIds([]); + setSelectedOrganization(''); + } + + useEffect(() => { + setUserIds(userIds); + }, [userIds]); + + async function handleCreateGroupChat(): Promise { + await createChat({ + variables: { + organizationId: selectedOrganization, + userIds: [userId, ...userIds], + name: title, + isGroup: true, + }, + }); + chatsListRefetch(); + toggleAddUserModal(); + toggleCreateGroupChatModal(); + reset(); + } + + const [userName, setUserName] = useState(''); + + const { + data: allUsersData, + loading: allUsersLoading, + refetch: allUsersRefetch, + } = useQuery(USERS_CONNECTION_LIST, { + variables: { + firstName_contains: '', + lastName_contains: '', + }, + }); + + const handleUserModalSearchChange = (e: React.FormEvent): void => { + e.preventDefault(); + /* istanbul ignore next */ + const [firstName, lastName] = userName.split(' '); + + const newFilterData = { + firstName_contains: firstName || '', + lastName_contains: lastName || '', + }; + + allUsersRefetch({ + ...newFilterData, + }); + }; + + useEffect(() => { + if (joinedOrganizationsData && joinedOrganizationsData.users.length > 0) { + const organizations = + joinedOrganizationsData.users[0]?.user?.joinedOrganizations || []; + setOrganizations(organizations); + } + }, [joinedOrganizationsData]); + + return ( + <> + + + New Group + + +
    + {/* + Select Organization + + */} + + Select Organization + + + + Group name + { + setTitle(e.target.value); + }} + /> + + +
    +
    +
    + + + {'Chat'} + + + {allUsersLoading ? ( + <> + + + ) : ( + <> +
    +
    + { + const { value } = e.target; + setUserName(value); + }} + /> + + +
    + + + + + + # + {'user'} + {'Chat'} + + + + {allUsersData && + allUsersData.users.length > 0 && + allUsersData.users.map( + ( + userDetails: InterfaceQueryUserListItem, + index: number, + ) => ( + + + {index + 1} + + + {userDetails.user.firstName + + ' ' + + userDetails.user.lastName} +
    + {userDetails.user.email} +
    + + {userIds.includes(userDetails.user._id) ? ( + + ) : ( + + )} + +
    + ), + )} +
    +
    +
    + + )} + +
    +
    + + ); +} diff --git a/src/components/UserPortal/DonationCard/DonationCard.test.tsx b/src/components/UserPortal/DonationCard/DonationCard.test.tsx index 4e49ed8b26..cddf62dd6c 100644 --- a/src/components/UserPortal/DonationCard/DonationCard.test.tsx +++ b/src/components/UserPortal/DonationCard/DonationCard.test.tsx @@ -1,5 +1,5 @@ -import React from 'react'; -import { act, render } from '@testing-library/react'; +import React, { act } from 'react'; +import { render } from '@testing-library/react'; import { MockedProvider } from '@apollo/react-testing'; import { I18nextProvider } from 'react-i18next'; diff --git a/src/components/UserPortal/DonationCard/DonationCard.tsx b/src/components/UserPortal/DonationCard/DonationCard.tsx index 696c5fb57b..63082f6acf 100644 --- a/src/components/UserPortal/DonationCard/DonationCard.tsx +++ b/src/components/UserPortal/DonationCard/DonationCard.tsx @@ -3,8 +3,24 @@ import styles from './DonationCard.module.css'; import { type InterfaceDonationCardProps } from 'screens/UserPortal/Donate/Donate'; import { Button } from 'react-bootstrap'; +/** + * Displays a card with details about a donation. + * + * Shows the donor's name, the amount donated, and the date of the donation. + * Includes a button to view more details about the donation. + * + * @param props - The properties passed to the component. + * @param name - The name of the donor. + * @param amount - The amount donated. + * @param updatedAt - The date of the donation, in ISO format. + * + * @returns The rendered donation card component. + */ function donationCard(props: InterfaceDonationCardProps): JSX.Element { + // Create a date object from the donation date string const date = new Date(props.updatedAt); + + // Format the date into a readable string const formattedDate = new Intl.DateTimeFormat('en-US', { weekday: 'short', year: 'numeric', diff --git a/src/components/UserPortal/EventCard/EventCard.tsx b/src/components/UserPortal/EventCard/EventCard.tsx index db8cd69785..e93138ce42 100644 --- a/src/components/UserPortal/EventCard/EventCard.tsx +++ b/src/components/UserPortal/EventCard/EventCard.tsx @@ -35,21 +35,59 @@ interface InterfaceEventCardProps { }[]; } +/** + * Displays information about an event and provides an option to register for it. + * + * Shows the event's title, description, location, start and end dates and times, + * creator's name, and registration status. Includes a button to register for the event + * if the user is not already registered. + * + * @param props - The properties for the event card. + * @param id - The unique identifier of the event. + * @param title - The title of the event. + * @param description - A description of the event. + * @param location - The location where the event will take place. + * @param startDate - The start date of the event in ISO format. + * @param endDate - The end date of the event in ISO format. + * @param isRegisterable - Indicates if the event can be registered for. + * @param isPublic - Indicates if the event is public. + * @param endTime - The end time of the event in HH:mm:ss format. + * @param startTime - The start time of the event in HH:mm:ss format. + * @param recurring - Indicates if the event is recurring. + * @param allDay - Indicates if the event lasts all day. + * @param creator - The creator of the event with their name and ID. + * @param registrants - A list of registrants with their IDs. + * + * @returns The event card component. + */ function eventCard(props: InterfaceEventCardProps): JSX.Element { + // Extract the translation functions const { t } = useTranslation('translation', { keyPrefix: 'userEventCard', }); const { t: tCommon } = useTranslation('common'); + + // Get user ID from local storage const { getItem } = useLocalStorage(); const userId = getItem('userId'); + + // Create a full name for the event creator const creatorName = `${props.creator.firstName} ${props.creator.lastName}`; + + // Check if the user is initially registered for the event const isInitiallyRegistered = props.registrants.some( (registrant) => registrant.id === userId, ); + // Set up the mutation for registering for the event const [registerEventMutation, { loading }] = useMutation(REGISTER_EVENT); const [isRegistered, setIsRegistered] = React.useState(isInitiallyRegistered); + /** + * Handles registering for the event. + * If the user is not already registered, sends a mutation request to register. + * Displays a success or error message based on the result. + */ const handleRegister = async (): Promise => { if (!isRegistered) { try { @@ -65,7 +103,7 @@ function eventCard(props: InterfaceEventCardProps): JSX.Element { } } catch (error: unknown) { /* istanbul ignore next */ - toast.error(error); + toast.error(error as string); } } }; diff --git a/src/components/UserPortal/Login/Login.module.css b/src/components/UserPortal/Login/Login.module.css deleted file mode 100644 index 98be9db02a..0000000000 --- a/src/components/UserPortal/Login/Login.module.css +++ /dev/null @@ -1,29 +0,0 @@ -.forgotPasswordContainer { - display: flex; - justify-content: flex-end; - flex-direction: row; - margin: 5px 0px; -} - -.forgotPasswordText { - color: black; - font-size: 12px; - margin: 2px 0px; -} - -.borderNone { - border: none; -} - -.colorWhite { - color: white; -} - -.colorPrimary { - background: #31bb6b; -} - -.colorPrimaryHover:hover { - background: #31bb6b; - border: none; -} diff --git a/src/components/UserPortal/Login/Login.test.tsx b/src/components/UserPortal/Login/Login.test.tsx deleted file mode 100644 index 9248c5e9ec..0000000000 --- a/src/components/UserPortal/Login/Login.test.tsx +++ /dev/null @@ -1,306 +0,0 @@ -import type { SetStateAction } from 'react'; -import React from 'react'; -import { act, render, screen } from '@testing-library/react'; -import { MockedProvider } from '@apollo/react-testing'; -import userEvent from '@testing-library/user-event'; -import { I18nextProvider } from 'react-i18next'; - -import { LOGIN_MUTATION } from 'GraphQl/Mutations/mutations'; -import { BrowserRouter } from 'react-router-dom'; -import { Provider } from 'react-redux'; -import { store } from 'state/store'; -import i18nForTest from 'utils/i18nForTest'; -import { StaticMockLink } from 'utils/StaticMockLink'; -import Login from './Login'; -import { toast } from 'react-toastify'; - -const MOCKS = [ - { - request: { - query: LOGIN_MUTATION, - variables: { - email: 'johndoe@gmail.com', - password: 'johndoe', - }, - }, - result: { - data: { - login: { - user: { - _id: '1', - firstName: 'firstname', - lastName: 'secondname', - email: 'tempemail@example.com', - image: 'image', - }, - accessToken: 'accessToken', - refreshToken: 'refreshToken', - appUserProfile: { - adminFor: [ - { - _id: 'id', - }, - ], - isSuperAdmin: true, - }, - }, - }, - }, - }, - { - request: { - query: LOGIN_MUTATION, - variables: { - email: 'johndoe@gmail.com', - password: 'jdoe', - }, - }, - result: { - data: { - login: { - user: { - _id: '1', - firstName: 'firstname', - lastName: 'secondname', - email: 'tempemail@example.com', - image: 'image', - }, - appUserProfile: { - adminFor: {}, - isSuperAdmin: false, - }, - accessToken: 'accessToken', - refreshToken: 'refreshToken', - }, - }, - }, - }, - { - request: { - query: LOGIN_MUTATION, - variables: { - email: 'invalid@gmail.com', - password: 'anything', - }, - }, - result: {}, - }, -]; - -const link = new StaticMockLink(MOCKS, true); - -async function wait(ms = 100): Promise { - await act(() => { - return new Promise((resolve) => { - setTimeout(resolve, ms); - }); - }); -} - -jest.mock('react-toastify', () => ({ - toast: { - success: jest.fn(), - warn: jest.fn(), - error: jest.fn(), - }, -})); -const mockNavigate = jest.fn(); -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useNavigate: () => mockNavigate, -})); - -const setCurrentMode: React.Dispatch> = jest.fn(); - -const props = { - setCurrentMode, -}; - -describe('Testing Login Component [User Portal]', () => { - test('Component should be rendered properly', async () => { - render( - - - - - - - - - , - ); - - await wait(); - }); - - test('Expect the mode to be changed to Register', async () => { - render( - - - - - - - - - , - ); - - await wait(); - - userEvent.click(screen.getByTestId('setRegisterBtn')); - - expect(setCurrentMode).toBeCalledWith('register'); - }); - - test('toast.error is triggered if the email input is empty.', async () => { - render( - - - - - - - - - , - ); - - await wait(); - - userEvent.click(screen.getByTestId('loginBtn')); - - expect(toast.error).toBeCalledWith( - 'Please enter a valid email and password.', - ); - }); - - test('toast.error is triggered if the password input is empty.', async () => { - const formData = { - email: 'johndoe@gmail.com', - password: 'joe', - }; - - render( - - - - - - - - - , - ); - - await wait(); - - userEvent.type(screen.getByPlaceholderText(/Enter Email/i), formData.email); - userEvent.click(screen.getByTestId('loginBtn')); - - expect(toast.error).toBeCalledWith( - 'Please enter a valid email and password.', - ); - }); - - test('Incorrect password is entered.', async () => { - const formData = { - email: 'invalid@gmail.com', - password: 'anything', - }; - - render( - - - - - - - - - , - ); - - await wait(); - - userEvent.type(screen.getByPlaceholderText(/Enter Email/i), formData.email); - - userEvent.type( - screen.getByPlaceholderText(/Enter Password/i), - formData.password, - ); - - userEvent.click(screen.getByTestId('loginBtn')); - - expect(toast.error).toBeCalled(); - - await wait(); - }); - - test('Login details are entered correctly.', async () => { - const formData = { - email: 'johndoe@gmail.com', - password: 'johndoe', - }; - - render( - - - - - - - - - , - ); - - await wait(); - - userEvent.type(screen.getByPlaceholderText(/Enter Email/i), formData.email); - - userEvent.type( - screen.getByPlaceholderText(/Enter Password/i), - formData.password, - ); - - userEvent.click(screen.getByTestId('loginBtn')); - - await wait(); - expect(mockNavigate).toHaveBeenCalledWith('/user/organizations'); - }); - - test('Current user has not been approved by admin.', async () => { - const formData = { - email: 'johndoe@gmail.com', - password: 'jdoe', - }; - - render( - - - - - - - - - , - ); - - await wait(); - - userEvent.type(screen.getByPlaceholderText(/Enter Email/i), formData.email); - - userEvent.type( - screen.getByPlaceholderText(/Enter Password/i), - formData.password, - ); - - userEvent.click(screen.getByTestId('loginBtn')); - - expect(toast.error).toBeCalled(); - - await wait(); - }); -}); diff --git a/src/components/UserPortal/Login/Login.tsx b/src/components/UserPortal/Login/Login.tsx deleted file mode 100644 index 517170263e..0000000000 --- a/src/components/UserPortal/Login/Login.tsx +++ /dev/null @@ -1,144 +0,0 @@ -import { useMutation } from '@apollo/client'; -import { LockOutlined } from '@mui/icons-material'; -import EmailOutlinedIcon from '@mui/icons-material/EmailOutlined'; -import type { ChangeEvent, SetStateAction } from 'react'; -import React from 'react'; -import { Button, Form, InputGroup } from 'react-bootstrap'; -import { useTranslation } from 'react-i18next'; -import { Link, useNavigate } from 'react-router-dom'; -import { toast } from 'react-toastify'; - -import { LOGIN_MUTATION } from 'GraphQl/Mutations/mutations'; -import { errorHandler } from 'utils/errorHandler'; -import useLocalStorage from 'utils/useLocalstorage'; -import styles from './Login.module.css'; - -interface InterfaceLoginProps { - setCurrentMode: React.Dispatch>; -} - -export default function login(props: InterfaceLoginProps): JSX.Element { - const { t } = useTranslation('translation', { keyPrefix: 'userLogin' }); - const { t: tCommon } = useTranslation('common'); - - const navigate = useNavigate(); - - const { setCurrentMode } = props; - - const { setItem } = useLocalStorage(); - - const handleModeChangeToRegister = (): void => { - setCurrentMode('register'); - }; - - const [loginMutation] = useMutation(LOGIN_MUTATION); - - const [loginVariables, setLoginVariables] = React.useState({ - email: '', - password: '', - }); - - const handleLogin = async (): Promise => { - if (!(loginVariables.email && loginVariables.password)) { - toast.error(t('invalidDetailsMessage')); - } else { - try { - const { data } = await loginMutation({ - variables: { - email: loginVariables.email, - password: loginVariables.password, - }, - }); - - setItem('token', data.login.accessToken); - setItem('userId', data.login.user._id); - navigate('/user/organizations'); - } catch (error: unknown) { - errorHandler(t, error); - } - } - }; - - /* istanbul ignore next */ - const handleEmailChange = (e: ChangeEvent): void => { - const email = e.target.value; - - setLoginVariables({ - email, - password: loginVariables.password, - }); - }; - - /* istanbul ignore next */ - const handlePasswordChange = (e: ChangeEvent): void => { - const password = e.target.value; - - setLoginVariables({ - email: loginVariables.email, - password, - }); - }; - - return ( - <> -

    {tCommon('login')}

    - -
    -
    {tCommon('emailAddress')}
    - - - - - - -
    {tCommon('password')}
    - - - - - - -
    - -
    - - {tCommon('forgotPassword')} - -
    - - -
    - - - ); -} diff --git a/src/components/UserPortal/OrganizationCard/OrganizationCard.test.tsx b/src/components/UserPortal/OrganizationCard/OrganizationCard.test.tsx index dba4286290..ba13fe346d 100644 --- a/src/components/UserPortal/OrganizationCard/OrganizationCard.test.tsx +++ b/src/components/UserPortal/OrganizationCard/OrganizationCard.test.tsx @@ -1,5 +1,5 @@ -import React from 'react'; -import { act, fireEvent, render, screen } from '@testing-library/react'; +import React, { act } from 'react'; +import { fireEvent, render, screen } from '@testing-library/react'; import { MockedProvider } from '@apollo/react-testing'; import { I18nextProvider } from 'react-i18next'; @@ -250,7 +250,7 @@ describe('Testing OrganizationCard Component [User Portal]', () => { fireEvent.click(screen.getByTestId('joinBtn')); await wait(); - expect(toast.success).toHaveBeenCalledWith('users.MembershipRequestSent'); + expect(toast.success).toHaveBeenCalledWith('MembershipRequestSent'); }); test('send membership request to public org', async () => { diff --git a/src/components/UserPortal/OrganizationCard/OrganizationCard.tsx b/src/components/UserPortal/OrganizationCard/OrganizationCard.tsx index fdb2d040d9..e1c2c23beb 100644 --- a/src/components/UserPortal/OrganizationCard/OrganizationCard.tsx +++ b/src/components/UserPortal/OrganizationCard/OrganizationCard.tsx @@ -48,6 +48,26 @@ interface InterfaceOrganizationCardProps { }[]; } +/** + * Displays an organization card with options to join or manage membership. + * + * Shows the organization's name, image, description, address, number of admins and members, + * and provides buttons for joining, withdrawing membership requests, or visiting the organization page. + * + * @param props - The properties for the organization card. + * @param id - The unique identifier of the organization. + * @param name - The name of the organization. + * @param image - The URL of the organization's image. + * @param description - A description of the organization. + * @param admins - The list of admins with their IDs. + * @param members - The list of members with their IDs. + * @param address - The address of the organization including city, country code, line1, postal code, and state. + * @param membershipRequestStatus - The status of the membership request (accepted, pending, or empty). + * @param userRegistrationRequired - Indicates if user registration is required to join the organization. + * @param membershipRequests - The list of membership requests with user IDs. + * + * @returns The organization card component. + */ const userId: string | null = getItem('userId'); function organizationCard(props: InterfaceOrganizationCardProps): JSX.Element { @@ -58,6 +78,7 @@ function organizationCard(props: InterfaceOrganizationCardProps): JSX.Element { const navigate = useNavigate(); + // Mutations for handling organization memberships const [sendMembershipRequest] = useMutation(SEND_MEMBERSHIP_REQUEST, { refetchQueries: [ { query: USER_ORGANIZATION_CONNECTION, variables: { id: props.id } }, @@ -77,6 +98,10 @@ function organizationCard(props: InterfaceOrganizationCardProps): JSX.Element { variables: { id: userId }, }); + /** + * Handles joining the organization. Sends a membership request if registration is required, + * otherwise joins the public organization directly. Displays success or error messages. + */ async function joinOrganization(): Promise { try { if (props.userRegistrationRequired) { @@ -85,28 +110,31 @@ function organizationCard(props: InterfaceOrganizationCardProps): JSX.Element { organizationId: props.id, }, }); - toast.success(t('MembershipRequestSent')); + toast.success(t('MembershipRequestSent') as string); } else { await joinPublicOrganization({ variables: { organizationId: props.id, }, }); - toast.success(t('orgJoined')); + toast.success(t('orgJoined') as string); } refetch(); } catch (error: unknown) { /* istanbul ignore next */ if (error instanceof Error) { if (error.message === 'User is already a member') { - toast.error(t('AlreadyJoined')); + toast.error(t('AlreadyJoined') as string); } else { - toast.error(t('errorOccured')); + toast.error(t('errorOccured') as string); } } } } + /** + * Handles withdrawing a membership request. Finds the request for the current user and cancels it. + */ async function withdrawMembershipRequest(): Promise { const membershipRequest = props.membershipRequests.find( (request) => request.user._id === userId, diff --git a/src/components/UserPortal/OrganizationNavbar/OrganizationNavbar.test.tsx b/src/components/UserPortal/OrganizationNavbar/OrganizationNavbar.test.tsx index 027234b641..038ff626df 100644 --- a/src/components/UserPortal/OrganizationNavbar/OrganizationNavbar.test.tsx +++ b/src/components/UserPortal/OrganizationNavbar/OrganizationNavbar.test.tsx @@ -1,7 +1,7 @@ -import React from 'react'; +import React, { act } from 'react'; import { MockedProvider } from '@apollo/react-testing'; import 'jest-localstorage-mock'; -import { act, render, screen } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import { I18nextProvider } from 'react-i18next'; import { Provider } from 'react-redux'; import { BrowserRouter, Router } from 'react-router-dom'; diff --git a/src/components/UserPortal/OrganizationNavbar/OrganizationNavbar.tsx b/src/components/UserPortal/OrganizationNavbar/OrganizationNavbar.tsx index 90cd75a83c..34022fcfcf 100644 --- a/src/components/UserPortal/OrganizationNavbar/OrganizationNavbar.tsx +++ b/src/components/UserPortal/OrganizationNavbar/OrganizationNavbar.tsx @@ -1,6 +1,6 @@ import React from 'react'; import styles from './OrganizationNavbar.module.css'; -import TalawaImage from 'assets/images/talawa-logo-200x200.png'; +import TalawaImage from 'assets/images/talawa-logo-600x600.png'; import { Container, Dropdown, Nav, Navbar, Offcanvas } from 'react-bootstrap'; import { languages } from 'utils/languages'; import i18next from 'i18next'; @@ -26,6 +26,21 @@ type Plugin = { translated: string; view: boolean; }; + +/** + * Displays the organization navbar with navigation options, user settings, and language selection. + * + * The navbar includes: + * - Organization branding and name. + * - Navigation links for various plugins based on user permissions. + * - Language dropdown for changing the interface language. + * - User dropdown for accessing settings and logging out. + * + * @param props - The properties for the navbar. + * @param currentPage - The current page identifier for highlighting the active navigation link. + * + * @returns The organization navbar component. + */ function organizationNavbar(props: InterfaceNavbarProps): JSX.Element { const { t } = useTranslation('translation', { keyPrefix: 'userNavbar', @@ -37,7 +52,7 @@ function organizationNavbar(props: InterfaceNavbarProps): JSX.Element { const [organizationDetails, setOrganizationDetails] = React.useState<{ name: string; }>({ name: '' }); - // const dropDirection: DropDirection = screen.width > 767 ? 'start' : 'down'; + const dropDirection: DropDirection = 'start'; const { orgId: organizationId } = useParams(); @@ -53,6 +68,9 @@ function organizationNavbar(props: InterfaceNavbarProps): JSX.Element { const { getItem, setItem } = useLocalStorage(); + /** + * Handles user logout by clearing local storage and redirecting to the home page. + */ /* istanbul ignore next */ const handleLogout = (): void => { localStorage.clear(); @@ -60,6 +78,7 @@ function organizationNavbar(props: InterfaceNavbarProps): JSX.Element { }; const userName = getItem('name'); + React.useEffect(() => { if (data) { setOrganizationDetails({ name: data.organizationsConnection[0].name }); @@ -67,6 +86,7 @@ function organizationNavbar(props: InterfaceNavbarProps): JSX.Element { }, [data]); const homeLink = `/user/organization/${organizationId}`; + let plugins: Plugin[] = [ { pluginName: 'People', @@ -97,15 +117,14 @@ function organizationNavbar(props: InterfaceNavbarProps): JSX.Element { // view: true, // }, ]; + if (getItem('talawaPlugins')) { const talawaPlugins: string = getItem('talawaPlugins') || '{}'; plugins = JSON.parse(talawaPlugins); } - const { data: updatedPluginData } = useSubscription( - PLUGIN_SUBSCRIPTION, - // { variables: { } } - ); + const { data: updatedPluginData } = useSubscription(PLUGIN_SUBSCRIPTION); + function getPluginIndex(pluginName: string, pluginsArray: Plugin[]): number { return pluginsArray.findIndex((plugin) => plugin.pluginName === pluginName); } @@ -129,6 +148,7 @@ function organizationNavbar(props: InterfaceNavbarProps): JSX.Element { } } } + return ( diff --git a/src/components/UserPortal/OrganizationSidebar/OrganizationSidebar.test.tsx b/src/components/UserPortal/OrganizationSidebar/OrganizationSidebar.test.tsx index c5fbcf335e..c08240462a 100644 --- a/src/components/UserPortal/OrganizationSidebar/OrganizationSidebar.test.tsx +++ b/src/components/UserPortal/OrganizationSidebar/OrganizationSidebar.test.tsx @@ -1,5 +1,5 @@ -import React from 'react'; -import { act, render, screen } from '@testing-library/react'; +import React, { act } from 'react'; +import { render, screen } from '@testing-library/react'; import { MockedProvider } from '@apollo/react-testing'; import { I18nextProvider } from 'react-i18next'; diff --git a/src/components/UserPortal/OrganizationSidebar/OrganizationSidebar.tsx b/src/components/UserPortal/OrganizationSidebar/OrganizationSidebar.tsx index 6e5aa42d70..796d30d568 100644 --- a/src/components/UserPortal/OrganizationSidebar/OrganizationSidebar.tsx +++ b/src/components/UserPortal/OrganizationSidebar/OrganizationSidebar.tsx @@ -18,40 +18,68 @@ import type { InterfaceMemberInfo, } from 'utils/interfaces'; +/** + * OrganizationSidebar displays the sidebar for an organization, showing a list of members and events. + * + * This component fetches and displays: + * - The top 3 members of the organization with their images and names. + * - The top 3 upcoming events for the organization with their titles, start, and end dates. + * + * It includes: + * - A link to view all members. + * - A link to view all events. + * + * The sidebar handles loading states and displays appropriate messages while data is being fetched. + * + * @returns JSX.Element representing the organization sidebar. + */ export default function organizationSidebar(): JSX.Element { + // Translation functions for different namespaces const { t } = useTranslation('translation', { keyPrefix: 'organizationSidebar', }); const { t: tCommon } = useTranslation('common'); + // Extract the organization ID from the URL parameters const { orgId: organizationId } = useParams(); - const [members, setMembers] = React.useState([]); - const [events, setEvents] = React.useState([]); - const eventsLink = `/user/events/id=${organizationId}`; - const peopleLink = `/user/people/id=${organizationId}`; + const [members, setMembers] = React.useState< + InterfaceMemberInfo[] | undefined + >(undefined); + const [events, setEvents] = React.useState< + InterfaceQueryOrganizationEventListItem[] | undefined + >(undefined); + const eventsLink = `/user/events/${organizationId}`; + const peopleLink = `/user/people/${organizationId}`; + // Query to fetch members of the organization const { data: memberData, loading: memberLoading } = useQuery( ORGANIZATIONS_MEMBER_CONNECTION_LIST, { variables: { orgId: organizationId, - first: 3, - skip: 0, + first: 3, // Fetch top 3 members + skip: 0, // No offset }, }, ); + // Query to fetch events of the organization const { data: eventsData, loading: eventsLoading } = useQuery( ORGANIZATION_EVENT_CONNECTION_LIST, { variables: { organization_id: organizationId, - first: 3, - skip: 0, + first: 3, // Fetch top 3 upcoming events + skip: 0, // No offset }, }, ); + /** + * Effect hook to update members state when memberData is fetched. + * + * Sets the members state with the data from the query. + */ /* istanbul ignore next */ useEffect(() => { if (memberData) { @@ -59,6 +87,11 @@ export default function organizationSidebar(): JSX.Element { } }, [memberData]); + /** + * Effect hook to update events state when eventsData is fetched. + * + * Sets the events state with the data from the query. + */ /* istanbul ignore next */ useEffect(() => { if (eventsData) { @@ -68,6 +101,7 @@ export default function organizationSidebar(): JSX.Element { return (
    + {/* Members section */}
    {tCommon('members')}
    @@ -77,44 +111,42 @@ export default function organizationSidebar(): JSX.Element {
    ) : ( - {members.length ? ( - members.map( - ( - member: InterfaceMemberInfo, - index: React.Key | null | undefined, - ) => { - const memberName = `${member.firstName} ${member.lastName}`; - return ( - -
    - -
    {memberName}
    -
    -
    - ); - }, - ) + {members && members.length ? ( + members.map((member: InterfaceMemberInfo) => { + const memberName = `${member.firstName} ${member.lastName}`; + return ( + +
    + +
    {memberName}
    +
    +
    + ); + }) ) : (
    {t('noMembers')}
    )}
    )} + {/* Link to view all members */}
    {t('viewAll')}
    + + {/* Events section */}
    {t('events')}
    @@ -124,42 +156,39 @@ export default function organizationSidebar(): JSX.Element {
    ) : ( - {events.length ? ( - events.map( - ( - event: InterfaceQueryOrganizationEventListItem, - index: React.Key | null | undefined, - ) => { - return ( - -
    -
    -
    {event.title}
    -
    - -
    -
    -
    - Starts{' '} - {dayjs(event.startDate).format("D MMMM 'YY")} -
    -
    - Ends {dayjs(event.endDate).format("D MMMM 'YY")} + {events && events.length ? ( + events.map((event: InterfaceQueryOrganizationEventListItem) => { + return ( + +
    +
    +
    {event.title}
    +
    +
    - - ); - }, - ) +
    + Starts{' '} + {dayjs(event.startDate).format("D MMMM 'YY")} +
    +
    + Ends {dayjs(event.endDate).format("D MMMM 'YY")} +
    +
    +
    + ); + }) ) : (
    {t('noEvents')}
    )} )} + + {/* Link to view all events */}
    {t('viewAll')} diff --git a/src/components/UserPortal/PeopleCard/PeopleCard.test.tsx b/src/components/UserPortal/PeopleCard/PeopleCard.test.tsx index 5cadfa923b..fd5d6c7f93 100644 --- a/src/components/UserPortal/PeopleCard/PeopleCard.test.tsx +++ b/src/components/UserPortal/PeopleCard/PeopleCard.test.tsx @@ -1,5 +1,5 @@ -import React from 'react'; -import { act, render } from '@testing-library/react'; +import React, { act } from 'react'; +import { render } from '@testing-library/react'; import { MockedProvider } from '@apollo/react-testing'; import { I18nextProvider } from 'react-i18next'; diff --git a/src/components/UserPortal/PeopleCard/PeopleCard.tsx b/src/components/UserPortal/PeopleCard/PeopleCard.tsx index ec06122359..e6b6088801 100644 --- a/src/components/UserPortal/PeopleCard/PeopleCard.tsx +++ b/src/components/UserPortal/PeopleCard/PeopleCard.tsx @@ -2,6 +2,9 @@ import React from 'react'; import aboutImg from 'assets/images/defaultImg.png'; import styles from './PeopleCard.module.css'; +/** + * Props interface for the PeopleCard component. + */ interface InterfaceOrganizationCardProps { id: string; name: string; @@ -11,15 +14,32 @@ interface InterfaceOrganizationCardProps { sno: string; } +/** + * PeopleCard component displays information about a person within an organization. + * + * It includes: + * - An image of the person or a default image if none is provided. + * - The serial number of the person. + * - The person's name. + * - The person's email address. + * - The person's role within the organization, styled with a border. + * + * @param props - The properties passed to the component. + * @returns JSX.Element representing a card with the person's details. + */ function peopleCard(props: InterfaceOrganizationCardProps): JSX.Element { + // Determine the image URL; use default image if no image URL is provided const imageUrl = props.image ? props.image : aboutImg; return (
    + {/* Container for serial number and image */} + {/* Serial number */} {props.sno} + {/* Person's image */} + {/* Person's name */} {props.name} + {/* Person's email */} {props.email} + {/* Person's role with additional styling */}
    {props.role} diff --git a/src/components/UserPortal/PostCard/PostCard.module.css b/src/components/UserPortal/PostCard/PostCard.module.css index 857c4d0799..e8edc2d82c 100644 --- a/src/components/UserPortal/PostCard/PostCard.module.css +++ b/src/components/UserPortal/PostCard/PostCard.module.css @@ -1,6 +1,4 @@ .cardStyles { - height: 28rem; - max-height: 30rem; width: 20rem; background-color: white; padding: 0; @@ -178,3 +176,8 @@ outline: none; background-color: #f1f3f6; } + +.postImage { + height: 300px; + object-fit: cover; +} diff --git a/src/components/UserPortal/PostCard/PostCard.test.tsx b/src/components/UserPortal/PostCard/PostCard.test.tsx index 1ba0459b6d..f7d9217308 100644 --- a/src/components/UserPortal/PostCard/PostCard.test.tsx +++ b/src/components/UserPortal/PostCard/PostCard.test.tsx @@ -1,6 +1,6 @@ -import React from 'react'; +import React, { act } from 'react'; import { MockedProvider } from '@apollo/react-testing'; -import { act, render, screen } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import { I18nextProvider } from 'react-i18next'; import { Provider } from 'react-redux'; import { BrowserRouter } from 'react-router-dom'; @@ -185,7 +185,7 @@ describe('Testing PostCard Component [User Portal]', () => { { id: '64eb13beca85de60ebe0ed0e', creator: { - _id: '63d6064458fce20ee25c3bf7', + id: '63d6064458fce20ee25c3bf7', firstName: 'Noble', lastName: 'Mittal', email: 'test@gmail.com', @@ -199,7 +199,7 @@ describe('Testing PostCard Component [User Portal]', () => { { id: '64eb13beca85de60ebe0ed0b', creator: { - _id: '63d6064458fce20ee25c3bf8', + id: '63d6064458fce20ee25c3bf8', firstName: 'Priyanshu', lastName: 'Bartwal', email: 'test1@gmail.com', @@ -338,7 +338,7 @@ describe('Testing PostCard Component [User Portal]', () => { userEvent.click(screen.getByTestId('editPostBtn')); await wait(); - expect(toast.success).toBeCalledWith('Successfully edited the Post.'); + expect(toast.success).toBeCalledWith('Post updated Successfully'); }); test('Delete post should work properly', async () => { diff --git a/src/components/UserPortal/PostCard/PostCard.tsx b/src/components/UserPortal/PostCard/PostCard.tsx index d1b84412fb..f8fcdaebca 100644 --- a/src/components/UserPortal/PostCard/PostCard.tsx +++ b/src/components/UserPortal/PostCard/PostCard.tsx @@ -53,6 +53,19 @@ interface InterfaceCommentCardProps { handleDislikeComment: (commentId: string) => void; } +/** + * PostCard component displays an individual post, including its details, interactions, and comments. + * + * The component allows users to: + * - View the post's details in a modal. + * - Edit or delete the post. + * - Like or unlike the post. + * - Add comments to the post. + * - Like or dislike individual comments. + * + * @param props - The properties passed to the component including post details, comments, and related actions. + * @returns JSX.Element representing a post card with interactive features. + */ export default function postCard(props: InterfacePostCard): JSX.Element { const { t } = useTranslation('translation', { keyPrefix: 'postCard', @@ -61,8 +74,12 @@ export default function postCard(props: InterfacePostCard): JSX.Element { const { getItem } = useLocalStorage(); + // Retrieve user ID from local storage const userId = getItem('userId'); + // Check if the post is liked by the current user const likedByUser = props.likedBy.some((likedBy) => likedBy.id === userId); + + // State variables const [comments, setComments] = React.useState(props.comments); const [numComments, setNumComments] = React.useState(props.commentCount); @@ -73,8 +90,10 @@ export default function postCard(props: InterfacePostCard): JSX.Element { const [showEditPost, setShowEditPost] = React.useState(false); const [postContent, setPostContent] = React.useState(props.text); + // Post creator's full name const postCreator = `${props.creator.firstName} ${props.creator.lastName}`; + // GraphQL mutations const [likePost, { loading: likeLoading }] = useMutation(LIKE_POST); const [unLikePost, { loading: unlikeLoading }] = useMutation(UNLIKE_POST); const [create, { loading: commentLoading }] = @@ -82,12 +101,18 @@ export default function postCard(props: InterfacePostCard): JSX.Element { const [editPost] = useMutation(UPDATE_POST_MUTATION); const [deletePost] = useMutation(DELETE_POST_MUTATION); + // Toggle the view post modal const toggleViewPost = (): void => setViewPost(!viewPost); + + // Toggle the edit post modal const toggleEditPost = (): void => setShowEditPost(!showEditPost); + + // Handle input changes for the post content const handlePostInput = (e: React.ChangeEvent): void => { setPostContent(e.target.value); }; + // Toggle like or unlike the post const handleToggleLike = async (): Promise => { if (isLikedByUser) { try { @@ -103,7 +128,7 @@ export default function postCard(props: InterfacePostCard): JSX.Element { } } catch (error: unknown) { /* istanbul ignore next */ - toast.error(error); + toast.error(error as string); } } else { try { @@ -119,11 +144,12 @@ export default function postCard(props: InterfacePostCard): JSX.Element { } } catch (error: unknown) { /* istanbul ignore next */ - toast.error(error); + toast.error(error as string); } } }; + // Handle changes to the comment input field const handleCommentInput = ( event: React.ChangeEvent, ): void => { @@ -131,6 +157,7 @@ export default function postCard(props: InterfacePostCard): JSX.Element { setCommentInput(comment); }; + // Dislike a comment const handleDislikeComment = (commentId: string): void => { const updatedComments = comments.map((comment) => { let updatedComment = { ...comment }; @@ -148,6 +175,8 @@ export default function postCard(props: InterfacePostCard): JSX.Element { }); setComments(updatedComments); }; + + // Like a comment const handleLikeComment = (commentId: string): void => { const updatedComments = comments.map((comment) => { let updatedComment = { ...comment }; @@ -166,6 +195,7 @@ export default function postCard(props: InterfacePostCard): JSX.Element { setComments(updatedComments); }; + // Create a new comment const createComment = async (): Promise => { try { const { data: createEventData } = await create({ @@ -180,10 +210,10 @@ export default function postCard(props: InterfacePostCard): JSX.Element { setCommentInput(''); setNumComments((numComments) => numComments + 1); - const newComment: any = { - id: createEventData.createComment._id, + const newComment: InterfaceCommentCardProps = { + id: createEventData.createComment.id, creator: { - id: createEventData.createComment.creator.id, + id: createEventData.createComment.creator._id, firstName: createEventData.createComment.creator.firstName, lastName: createEventData.createComment.creator.lastName, email: createEventData.createComment.creator.email, @@ -203,6 +233,7 @@ export default function postCard(props: InterfacePostCard): JSX.Element { } }; + // Edit the post const handleEditPost = (): void => { try { editPost({ @@ -212,14 +243,16 @@ export default function postCard(props: InterfacePostCard): JSX.Element { }, }); - props.fetchPosts(); + props.fetchPosts(); // Refresh the posts toggleEditPost(); - toast.success('Successfully edited the Post.'); + toast.success(tCommon('updatedSuccessfully', { item: 'Post' }) as string); } catch (error: unknown) { /* istanbul ignore next */ errorHandler(t, error); } }; + + // Delete the post const handleDeletePost = (): void => { try { deletePost({ @@ -228,7 +261,7 @@ export default function postCard(props: InterfacePostCard): JSX.Element { }, }); - props.fetchPosts(); + props.fetchPosts(); // Refresh the posts toast.success('Successfully deleted the Post.'); } catch (error: unknown) { /* istanbul ignore next */ @@ -274,6 +307,7 @@ export default function postCard(props: InterfacePostCard): JSX.Element { - Posted On: {props.postedAt} + {t('postedOn', { date: props.postedAt })} {props.text} - {props.image && ( - - )}
    @@ -304,7 +335,7 @@ export default function postCard(props: InterfacePostCard): JSX.Element { data-testid={'viewPostBtn'} onClick={toggleViewPost} > - View Post + {t('viewPost')}
    @@ -341,7 +372,7 @@ export default function postCard(props: InterfacePostCard): JSX.Element {

    Comments

    {numComments ? ( - comments.map((comment: any, index: any) => { + comments.map((comment, index: number) => { const cardProps: InterfaceCommentCardProps = { id: comment.id, creator: { @@ -417,7 +448,7 @@ export default function postCard(props: InterfacePostCard): JSX.Element {

    - Edit Post + {t('editPost')}

    @@ -441,7 +472,7 @@ export default function postCard(props: InterfacePostCard): JSX.Element { data-testid={'editPostBtn'} onClick={handleEditPost} > - Edit Post + {t('editPost')}
    diff --git a/src/components/UserPortal/PromotedPost/PromotedPost.test.tsx b/src/components/UserPortal/PromotedPost/PromotedPost.test.tsx index b5d753551c..6ec8ec5de7 100644 --- a/src/components/UserPortal/PromotedPost/PromotedPost.test.tsx +++ b/src/components/UserPortal/PromotedPost/PromotedPost.test.tsx @@ -1,5 +1,5 @@ -import React from 'react'; -import { act, render, waitFor } from '@testing-library/react'; +import React, { act } from 'react'; +import { render, waitFor } from '@testing-library/react'; import { MockedProvider } from '@apollo/react-testing'; import { I18nextProvider } from 'react-i18next'; diff --git a/src/components/UserPortal/PromotedPost/PromotedPost.tsx b/src/components/UserPortal/PromotedPost/PromotedPost.tsx index 72ee107217..c1af98f367 100644 --- a/src/components/UserPortal/PromotedPost/PromotedPost.tsx +++ b/src/components/UserPortal/PromotedPost/PromotedPost.tsx @@ -2,11 +2,24 @@ import React from 'react'; import { Card } from 'react-bootstrap'; import styles from './PromotedPost.module.css'; import StarPurple500Icon from '@mui/icons-material/StarPurple500'; + interface InterfacePostCardProps { id: string; image: string; title: string; } + +/** + * PromotedPost component displays a card representing promoted content. + * + * This component includes: + * - A header with a star icon indicating the content is promoted. + * - A title and description of the promoted content. + * - An optional image associated with the promoted content. + * + * @param props - Properties passed to the component including an image, title, and ID. + * @returns JSX.Element representing a card with promoted content. + */ export default function promotedPost( props: InterfacePostCardProps, ): JSX.Element { @@ -15,13 +28,17 @@ export default function promotedPost(
    + {/* Icon indicating promoted content */} {'Promoted Content'}
    + {/* Display the title of the promoted content */} {props.title} + {/* Display a brief description or the title again */} {props.title} + {/* Conditionally render the image if provided */} {props.image && ( )} diff --git a/src/components/UserPortal/Register/Register.test.tsx b/src/components/UserPortal/Register/Register.test.tsx index cdcfb9ebc0..f9929a0588 100644 --- a/src/components/UserPortal/Register/Register.test.tsx +++ b/src/components/UserPortal/Register/Register.test.tsx @@ -1,6 +1,6 @@ import type { SetStateAction } from 'react'; -import React from 'react'; -import { act, render, screen } from '@testing-library/react'; +import React, { act } from 'react'; +import { render, screen } from '@testing-library/react'; import { MockedProvider } from '@apollo/react-testing'; import userEvent from '@testing-library/user-event'; import { I18nextProvider } from 'react-i18next'; diff --git a/src/components/UserPortal/Register/Register.tsx b/src/components/UserPortal/Register/Register.tsx index a9a4a52d85..11a810c955 100644 --- a/src/components/UserPortal/Register/Register.tsx +++ b/src/components/UserPortal/Register/Register.tsx @@ -13,21 +13,30 @@ import { toast } from 'react-toastify'; import { errorHandler } from 'utils/errorHandler'; interface InterfaceRegisterProps { + /** + * Function to change the current mode (e.g., from register to login). + */ setCurrentMode: React.Dispatch>; } export default function register(props: InterfaceRegisterProps): JSX.Element { const { setCurrentMode } = props; + // Translation hooks for user registration and common text const { t } = useTranslation('translation', { keyPrefix: 'userRegister' }); const { t: tCommon } = useTranslation('common'); + /** + * Changes the mode to login when invoked. + */ const handleModeChangeToLogin = (): void => { setCurrentMode('login'); }; + // Mutation hook for user registration const [registerMutation] = useMutation(SIGNUP_MUTATION); + // State to manage the registration form variables const [registerVariables, setRegisterVariables] = React.useState({ firstName: '', lastName: '', @@ -36,6 +45,9 @@ export default function register(props: InterfaceRegisterProps): JSX.Element { confirmPassword: '', }); + /** + * Handles the registration process by validating inputs and invoking the mutation. + */ const handleRegister = async (): Promise => { if ( !( @@ -45,11 +57,11 @@ export default function register(props: InterfaceRegisterProps): JSX.Element { registerVariables.lastName ) ) { - toast.error(t('invalidDetailsMessage')); + toast.error(t('invalidDetailsMessage') as string); // Error if fields are missing } else if ( registerVariables.password !== registerVariables.confirmPassword ) { - toast.error(t('passwordNotMatch')); + toast.error(t('passwordNotMatch') as string); // Error if passwords do not match } else { try { await registerMutation({ @@ -61,8 +73,9 @@ export default function register(props: InterfaceRegisterProps): JSX.Element { }, }); - toast.success(t('afterRegister')); + toast.success(t('afterRegister') as string); // Success message + // Reset form fields /* istanbul ignore next */ setRegisterVariables({ firstName: '', @@ -72,33 +85,47 @@ export default function register(props: InterfaceRegisterProps): JSX.Element { confirmPassword: '', }); } catch (error: unknown) { + // Handle any errors during registration /* istanbul ignore next */ errorHandler(t, error); } } }; + /** + * Updates the state with the first name input value. + * @param e - Change event from the input element + */ /* istanbul ignore next */ const handleFirstName = (e: ChangeEvent): void => { const firstName = e.target.value; - setRegisterVariables({ ...registerVariables, firstName }); }; + /** + * Updates the state with the last name input value. + * @param e - Change event from the input element + */ /* istanbul ignore next */ const handleLastName = (e: ChangeEvent): void => { const lastName = e.target.value; - setRegisterVariables({ ...registerVariables, lastName }); }; + /** + * Updates the state with the email input value. + * @param e - Change event from the input element + */ /* istanbul ignore next */ const handleEmailChange = (e: ChangeEvent): void => { const email = e.target.value; - setRegisterVariables({ ...registerVariables, email }); }; + /** + * Updates the state with the password input value. + * @param e - Change event from the input element + */ /* istanbul ignore next */ const handlePasswordChange = (e: ChangeEvent): void => { const password = e.target.value; @@ -106,6 +133,10 @@ export default function register(props: InterfaceRegisterProps): JSX.Element { setRegisterVariables({ ...registerVariables, password }); }; + /** + * Updates the state with the confirm password input value. + * @param e - Change event from the input element + */ /* istanbul ignore next */ const handleConfirmPasswordChange = ( e: ChangeEvent, diff --git a/src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.tsx b/src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.tsx index f21047579d..21d091dad6 100644 --- a/src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.tsx +++ b/src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.tsx @@ -3,10 +3,23 @@ import { Navigate, Outlet } from 'react-router-dom'; import PageNotFound from 'screens/PageNotFound/PageNotFound'; import useLocalStorage from 'utils/useLocalstorage'; +/** + * A component that guards routes by checking if the user is logged in. + * If the user is logged in and does not have 'AdminFor' set, the child routes are rendered. + * If the user is not logged in, they are redirected to the homepage. + * If the user is logged in but has 'AdminFor' set, a 404 page is shown. + * + * @returns JSX.Element - Rendered component based on user authentication and role. + */ const SecuredRouteForUser = (): JSX.Element => { + // Custom hook to interact with local storage const { getItem } = useLocalStorage(); + + // Check if the user is logged in and the role of the user const isLoggedIn = getItem('IsLoggedIn'); const adminFor = getItem('AdminFor'); + + // Conditional rendering based on authentication status and role return isLoggedIn === 'TRUE' ? ( <>{adminFor == undefined ? : } ) : ( diff --git a/src/components/UserPortal/StartPostModal/StartPostModal.test.tsx b/src/components/UserPortal/StartPostModal/StartPostModal.test.tsx index 5a2e815af4..5c436705cd 100644 --- a/src/components/UserPortal/StartPostModal/StartPostModal.test.tsx +++ b/src/components/UserPortal/StartPostModal/StartPostModal.test.tsx @@ -1,7 +1,7 @@ -import React from 'react'; +import React, { act } from 'react'; import { MockedProvider } from '@apollo/react-testing'; import type { RenderResult } from '@testing-library/react'; -import { act, fireEvent, render, screen } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import { I18nextProvider } from 'react-i18next'; import userEvent from '@testing-library/user-event'; import { CREATE_POST_MUTATION } from 'GraphQl/Mutations/mutations'; diff --git a/src/components/UserPortal/StartPostModal/StartPostModal.tsx b/src/components/UserPortal/StartPostModal/StartPostModal.tsx index 036bcd904e..d48b8425fa 100644 --- a/src/components/UserPortal/StartPostModal/StartPostModal.tsx +++ b/src/components/UserPortal/StartPostModal/StartPostModal.tsx @@ -20,6 +20,23 @@ interface InterfaceStartPostModalProps { img: string | null; } +/** + * A modal component for creating a new post. + * + * This modal includes: + * - A form where users can input the content of the post. + * - A preview of the image if provided. + * - User's profile image and name displayed in the modal header. + * + * @param show - Whether the modal is visible. + * @param onHide - Function to call when the modal is hidden. + * @param fetchPosts - Function to refresh the posts after creating a new one. + * @param userData - User data to display in the modal header. + * @param organizationId - The ID of the organization for the post. + * @param img - The URL of the image to be included in the post. + * + * @returns JSX.Element - The rendered modal component. + */ const startPostModal = ({ show, onHide, @@ -28,20 +45,36 @@ const startPostModal = ({ organizationId, img, }: InterfaceStartPostModalProps): JSX.Element => { + // Translation hook for internationalization const { t } = useTranslation('translation', { keyPrefix: 'home' }); + + // State to manage the content of the post const [postContent, setPostContent] = useState(''); + // Mutation hook for creating a new post const [createPost] = useMutation(CREATE_POST_MUTATION); + /** + * Updates the state with the content of the post as the user types. + * + * @param e - Change event from the textarea input. + */ const handlePostInput = (e: ChangeEvent): void => { setPostContent(e.target.value); }; + /** + * Hides the modal and clears the post content. + */ const handleHide = (): void => { setPostContent(''); onHide(); }; + /** + * Handles the creation of a new post by calling the mutation. + * Displays a toast notification based on the outcome. + */ const handlePost = async (): Promise => { try { if (!postContent) { @@ -60,7 +93,7 @@ const startPostModal = ({ /* istanbul ignore next */ if (data) { toast.dismiss(); - toast.success('Your post is now visible in the feed.'); + toast.success(t('postNowVisibleInFeed') as string); fetchPosts(); handleHide(); } diff --git a/src/components/UserPortal/UserNavbar/UserNavbar.test.tsx b/src/components/UserPortal/UserNavbar/UserNavbar.test.tsx index 59e3585aa0..8c3447f25a 100644 --- a/src/components/UserPortal/UserNavbar/UserNavbar.test.tsx +++ b/src/components/UserPortal/UserNavbar/UserNavbar.test.tsx @@ -1,6 +1,6 @@ -import React from 'react'; +import React, { act } from 'react'; import { MockedProvider } from '@apollo/react-testing'; -import { act, render, screen } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import { I18nextProvider } from 'react-i18next'; import { Provider } from 'react-redux'; import { BrowserRouter } from 'react-router-dom'; diff --git a/src/components/UserPortal/UserNavbar/UserNavbar.tsx b/src/components/UserPortal/UserNavbar/UserNavbar.tsx index f58c061440..4160b00aad 100644 --- a/src/components/UserPortal/UserNavbar/UserNavbar.tsx +++ b/src/components/UserPortal/UserNavbar/UserNavbar.tsx @@ -1,6 +1,6 @@ import React from 'react'; import styles from './UserNavbar.module.css'; -import TalawaImage from 'assets/images/talawa-logo-200x200.png'; +import TalawaImage from 'assets/images/talawa-logo-600x600.png'; import { Container, Dropdown, Navbar } from 'react-bootstrap'; import { languages } from 'utils/languages'; import i18next from 'i18next'; @@ -13,24 +13,45 @@ import { REVOKE_REFRESH_TOKEN } from 'GraphQl/Mutations/mutations'; import { useNavigate } from 'react-router-dom'; import useLocalStorage from 'utils/useLocalstorage'; +/** + * Navbar component for user-specific actions and settings. + * + * This component provides: + * - A branding image and name. + * - A dropdown for language selection. + * - A dropdown for user actions including profile settings and logout. + * + * @returns JSX.Element - The rendered Navbar component. + */ function userNavbar(): JSX.Element { + // Hook for local storage operations const { getItem } = useLocalStorage(); + + // Hook for programmatic navigation const navigate = useNavigate(); + // Translation hook for internationalization const { t } = useTranslation('translation', { keyPrefix: 'userNavbar', }); const { t: tCommon } = useTranslation('common'); + // Mutation hook for revoking the refresh token const [revokeRefreshToken] = useMutation(REVOKE_REFRESH_TOKEN); + // State for managing the current language code const [currentLanguageCode, setCurrentLanguageCode] = React.useState( /* istanbul ignore next */ cookies.get('i18next') || 'en', ); + // Retrieve the username from local storage const userName = getItem('name'); + /** + * Handles user logout by revoking the refresh token and clearing local storage. + * Redirects to the home page after logout. + */ /* istanbul ignore next */ const handleLogout = (): void => { revokeRefreshToken(); @@ -41,6 +62,7 @@ function userNavbar(): JSX.Element { return ( + {/* Navbar brand with logo and name */} {t('talawa')} + {/* Navbar toggle button for responsive design */} + + {/* Navbar collapsible content */} + {/* Dropdown for language selection */} + {/* Dropdown for user actions */} + {/* Display the user's name */} {userName} + {/* Link to user settings */} navigate('/user/settings')} className={styles.link} > {tCommon('settings')} + {/* Logout button */} {tCommon('logout')} diff --git a/src/components/UserPortal/UserSidebar/UserSidebar.module.css b/src/components/UserPortal/UserSidebar/UserSidebar.module.css index a9d330339f..aafeaeff97 100644 --- a/src/components/UserPortal/UserSidebar/UserSidebar.module.css +++ b/src/components/UserPortal/UserSidebar/UserSidebar.module.css @@ -1,5 +1,5 @@ .leftDrawer { - width: calc(300px + 2rem); + width: calc(300px); position: fixed; top: 0; bottom: 0; @@ -13,7 +13,7 @@ } .activeDrawer { - width: calc(300px + 2rem); + width: calc(300px); position: fixed; top: 0; left: 0; diff --git a/src/components/UserPortal/UserSidebar/UserSidebar.test.tsx b/src/components/UserPortal/UserSidebar/UserSidebar.test.tsx index 2984604951..7218bc745c 100644 --- a/src/components/UserPortal/UserSidebar/UserSidebar.test.tsx +++ b/src/components/UserPortal/UserSidebar/UserSidebar.test.tsx @@ -1,6 +1,6 @@ -import React from 'react'; +import React, { act } from 'react'; import type { RenderResult } from '@testing-library/react'; -import { act, fireEvent, render, screen } from '@testing-library/react'; +import { fireEvent, render, screen, waitFor } from '@testing-library/react'; import { MockedProvider } from '@apollo/react-testing'; import { I18nextProvider } from 'react-i18next'; @@ -19,14 +19,17 @@ import useLocalStorage from 'utils/useLocalstorage'; const { setItem } = useLocalStorage(); const resizeWindow = (width: number): void => { - window.innerWidth = width; - fireEvent(window, new Event('resize')); + act(() => { + window.innerWidth = width; + fireEvent(window, new Event('resize')); + }); }; const props = { hideDrawer: true, setHideDrawer: jest.fn(), }; + const MOCKS = [ { request: { @@ -366,38 +369,48 @@ describe('Testing UserSidebar Component [User Portal]', () => { }); test('Component should be rendered properly', async () => { - renderUserSidebar('properId', link); - await wait(); + await act(async () => { + renderUserSidebar('properId', link); + await wait(); + }); }); test('Component should be rendered properly when userImage is present', async () => { - renderUserSidebar('imagePresent', link); - await wait(); + await act(async () => { + renderUserSidebar('imagePresent', link); + await wait(); + }); }); test('Component should be rendered properly when organizationImage is present', async () => { - renderUserSidebar('imagePresent', link); - await wait(); + await act(async () => { + renderUserSidebar('imagePresent', link); + await wait(); + }); }); test('Component should be rendered properly when joinedOrganizations list is empty', async () => { - renderUserSidebar('orgEmpty', link); - await wait(); + await act(async () => { + renderUserSidebar('orgEmpty', link); + await wait(); + }); }); - test('Testing Drawer when the screen size is less than or equal to 820px', () => { - resizeWindow(800); - render( - - - - - - - - - , - ); + test('Testing Drawer when the screen size is less than or equal to 820px', async () => { + await act(async () => { + resizeWindow(800); + render( + + + + + + + + + , + ); + }); expect(screen.getByText('My Organizations')).toBeInTheDocument(); expect(screen.getByText('Settings')).toBeInTheDocument(); expect(screen.getByText('Talawa User Portal')).toBeInTheDocument(); @@ -405,13 +418,21 @@ describe('Testing UserSidebar Component [User Portal]', () => { const orgsBtn = screen.getAllByTestId(/orgsBtn/i); - orgsBtn[0].click(); - expect( - orgsBtn[0].className.includes('text-white btn btn-success'), - ).toBeTruthy(); - settingsBtn.click(); - expect( - settingsBtn.className.includes('text-white btn btn-success'), - ).toBeTruthy(); + act(() => { + orgsBtn[0].click(); + }); + await waitFor(() => + expect( + orgsBtn[0].className.includes('text-white btn btn-success'), + ).toBeTruthy(), + ); + act(() => { + settingsBtn.click(); + }); + await waitFor(() => + expect( + settingsBtn.className.includes('text-white btn btn-success'), + ).toBeTruthy(), + ); }); }); diff --git a/src/components/UserPortal/UserSidebar/UserSidebar.tsx b/src/components/UserPortal/UserSidebar/UserSidebar.tsx index 563172fc07..5e258f8a8e 100644 --- a/src/components/UserPortal/UserSidebar/UserSidebar.tsx +++ b/src/components/UserPortal/UserSidebar/UserSidebar.tsx @@ -2,9 +2,10 @@ import React from 'react'; import Button from 'react-bootstrap/Button'; import { useTranslation } from 'react-i18next'; import { NavLink } from 'react-router-dom'; -import { ReactComponent as OrganizationsIcon } from 'assets/svgs/organizations.svg'; -import { ReactComponent as SettingsIcon } from 'assets/svgs/settings.svg'; -import { ReactComponent as TalawaLogo } from 'assets/svgs/talawa.svg'; +import OrganizationsIcon from 'assets/svgs/organizations.svg?react'; +import SettingsIcon from 'assets/svgs/settings.svg?react'; +import ChatIcon from 'assets/svgs/chat.svg?react'; +import TalawaLogo from 'assets/svgs/talawa.svg?react'; import styles from './UserSidebar.module.css'; export interface InterfaceUserSidebarProps { @@ -12,13 +13,31 @@ export interface InterfaceUserSidebarProps { setHideDrawer: React.Dispatch>; } +/** + * Sidebar component for user navigation, including links to organizations and settings. + * + * Provides: + * - A logo and title for the sidebar. + * - Navigation buttons for "My Organizations" and "Settings". + * - Dynamic styling based on the active route. + * + * @param hideDrawer - Boolean indicating if the sidebar should be hidden or shown. + * @param setHideDrawer - Function to update the `hideDrawer` state. + * + * @returns JSX.Element - The rendered sidebar component. + */ const userSidebar = ({ hideDrawer, setHideDrawer, }: InterfaceUserSidebarProps): JSX.Element => { + // Translation hook for internationalization const { t } = useTranslation('translation', { keyPrefix: 'userSidebarOrg' }); const { t: tCommon } = useTranslation('common'); + /** + * Handles click events on navigation links. + * Closes the sidebar if the viewport width is 820px or less. + */ const handleLinkClick = (): void => { if (window.innerWidth <= 820) { setHideDrawer(true); @@ -37,12 +56,14 @@ const userSidebar = ({ }`} data-testid="leftDrawerContainer" > + {/* Logo and title */}

    {t('talawaUserPortal')}

    {tCommon('menu')}
    + {/* Link to "My Organizations" page */} {({ isActive }) => ( + )} +
    diff --git a/src/components/UserPortal/UserSidebarOrg/UserSidebarOrg.test.tsx b/src/components/UserPortal/UserSidebarOrg/UserSidebarOrg.test.tsx index d9d70478b3..2f28d9afd1 100644 --- a/src/components/UserPortal/UserSidebarOrg/UserSidebarOrg.test.tsx +++ b/src/components/UserPortal/UserSidebarOrg/UserSidebarOrg.test.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { act } from 'react'; import { fireEvent, render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import 'jest-localstorage-mock'; @@ -12,7 +12,6 @@ import { Provider } from 'react-redux'; import { MockedProvider } from '@apollo/react-testing'; import { store } from 'state/store'; import { ORGANIZATIONS_LIST } from 'GraphQl/Queries/Queries'; -import { act } from 'react-dom/test-utils'; import { StaticMockLink } from 'utils/StaticMockLink'; import { REVOKE_REFRESH_TOKEN } from 'GraphQl/Mutations/mutations'; import useLocalStorage from 'utils/useLocalstorage'; @@ -332,7 +331,7 @@ describe('Testing LeftDrawerOrg component for SUPERADMIN', () => { ); await wait(); resizeWindow(800); - expect(screen.getByText(/People/i)).toBeInTheDocument(); + expect(screen.getAllByText(/People/i)[0]).toBeInTheDocument(); const peopelBtn = screen.getByTestId(/People/i); userEvent.click(peopelBtn); diff --git a/src/components/UserPortal/UserSidebarOrg/UserSidebarOrg.tsx b/src/components/UserPortal/UserSidebarOrg/UserSidebarOrg.tsx index 7d78d3765e..19036b2307 100644 --- a/src/components/UserPortal/UserSidebarOrg/UserSidebarOrg.tsx +++ b/src/components/UserPortal/UserSidebarOrg/UserSidebarOrg.tsx @@ -9,8 +9,8 @@ import { useTranslation } from 'react-i18next'; import { NavLink } from 'react-router-dom'; import type { TargetsType } from 'state/reducers/routesReducer'; import type { InterfaceQueryOrganizationsListObject } from 'utils/interfaces'; -import { ReactComponent as AngleRightIcon } from 'assets/svgs/angleRight.svg'; -import { ReactComponent as TalawaLogo } from 'assets/svgs/talawa.svg'; +import AngleRightIcon from 'assets/svgs/angleRight.svg?react'; +import TalawaLogo from 'assets/svgs/talawa.svg?react'; import styles from './UserSidebarOrg.module.css'; import Avatar from 'components/Avatar/Avatar'; @@ -21,18 +21,39 @@ export interface InterfaceUserSidebarOrgProps { setHideDrawer: React.Dispatch>; } +/** + * Sidebar component for user navigation within an organization. + * + * Provides: + * - Branding with the Talawa logo. + * - Displays the current organization's details. + * - Navigation options with links and collapsible dropdowns. + * + * @param orgId - ID of the current organization. + * @param targets - List of navigation targets. + * @param hideDrawer - Boolean indicating if the sidebar should be hidden or shown. + * @param setHideDrawer - Function to update the `hideDrawer` state. + * + * @returns JSX.Element - The rendered sidebar component. + */ const UserSidebarOrg = ({ targets, orgId, hideDrawer, setHideDrawer, }: InterfaceUserSidebarOrgProps): JSX.Element => { + // Translation hook for internationalization const { t } = useTranslation('translation', { keyPrefix: 'userSidebarOrg' }); const { t: tCommon } = useTranslation('common'); + + // State for managing dropdown visibility const [showDropdown, setShowDropdown] = React.useState(false); + // State for organization data const [organization, setOrganization] = useState(); + + // Query to fetch organization data const { data, loading, @@ -44,18 +65,22 @@ const UserSidebarOrg = ({ } = useQuery(ORGANIZATIONS_LIST, { variables: { id: orgId }, }); - // Set organization data + + // Set organization data once the query is complete useEffect(() => { let isMounted = true; if (data && isMounted) { setOrganization(data?.organizations[0]); - console.log(targets, 'targets'); } return () => { isMounted = false; }; }, [data]); + /** + * Handles click events on navigation links. + * Closes the sidebar if the viewport width is 820px or less. + */ const handleLinkClick = (): void => { if (window.innerWidth <= 820) { setHideDrawer(true); @@ -150,7 +175,7 @@ const UserSidebarOrg = ({ } />
    - {name} + {tCommon(name)} )} diff --git a/src/components/UserProfileSettings/DeleteUser.tsx b/src/components/UserProfileSettings/DeleteUser.tsx index 3a90542883..90b5f25433 100644 --- a/src/components/UserProfileSettings/DeleteUser.tsx +++ b/src/components/UserProfileSettings/DeleteUser.tsx @@ -3,6 +3,12 @@ import { Button, Card } from 'react-bootstrap'; import { useTranslation } from 'react-i18next'; import styles from './UserProfileSettings.module.css'; +/** + * DeleteUser component displays a card with a button to delete a user. + * It includes a message and a button to trigger the delete action. + * + * @returns The JSX element for the delete user card. + */ const DeleteUser: React.FC = () => { const { t } = useTranslation('translation', { keyPrefix: 'settings', diff --git a/src/components/UserProfileSettings/OtherSettings.tsx b/src/components/UserProfileSettings/OtherSettings.tsx index 1e9723c2d6..e83632c8b1 100644 --- a/src/components/UserProfileSettings/OtherSettings.tsx +++ b/src/components/UserProfileSettings/OtherSettings.tsx @@ -4,6 +4,12 @@ import { Card, Form } from 'react-bootstrap'; import { useTranslation } from 'react-i18next'; import styles from './UserProfileSettings.module.css'; +/** + * OtherSettings component displays a card with settings options such as changing the language. + * It includes a label and a dropdown for selecting a different language. + * + * @returns The JSX element for the other settings card. + */ const OtherSettings: React.FC = () => { const { t } = useTranslation('translation', { keyPrefix: 'settings', diff --git a/src/components/UserProfileSettings/UserProfile.test.tsx b/src/components/UserProfileSettings/UserProfile.test.tsx index 979310685f..82caad5d81 100644 --- a/src/components/UserProfileSettings/UserProfile.test.tsx +++ b/src/components/UserProfileSettings/UserProfile.test.tsx @@ -9,8 +9,9 @@ import i18nForTest from 'utils/i18nForTest'; describe('UserProfile component', () => { test('renders user profile details correctly', () => { const userDetails = { - firstName: 'John', + firstName: 'Christopher', lastName: 'Doe', + createdAt: '2023-04-13T04:53:17.742+00:00', email: 'john.doe@example.com', image: 'profile-image-url', }; @@ -24,14 +25,14 @@ describe('UserProfile component', () => { , ); - expect(getByText('John')).toBeInTheDocument(); - expect(getByText('john.doe@example.com')).toBeInTheDocument(); + expect(getByText('Chris..')).toBeInTheDocument(); + expect(getByText('john..@example.com')).toBeInTheDocument(); const profileImage = getByAltText('profile picture'); expect(profileImage).toBeInTheDocument(); expect(profileImage).toHaveAttribute('src', 'profile-image-url'); - expect(getByText('Joined 1st May, 2021')).toBeInTheDocument(); + expect(getByText('Joined 13 April 2023')).toBeInTheDocument(); expect(getByText('Copy Profile Link')).toBeInTheDocument(); }); diff --git a/src/components/UserProfileSettings/UserProfile.tsx b/src/components/UserProfileSettings/UserProfile.tsx index 77e1542c82..9d24c15480 100644 --- a/src/components/UserProfileSettings/UserProfile.tsx +++ b/src/components/UserProfileSettings/UserProfile.tsx @@ -4,17 +4,41 @@ import { Button, Card } from 'react-bootstrap'; import CalendarMonthOutlinedIcon from '@mui/icons-material/CalendarMonthOutlined'; import { useTranslation } from 'react-i18next'; import styles from './UserProfileSettings.module.css'; +import { Tooltip as ReactTooltip } from 'react-tooltip'; interface InterfaceUserProfile { firstName: string; lastName: string; + createdAt: string; email: string; image: string; } +const joinedDate = (param: string): string => { + const date = new Date(param); + if (date?.toDateString() === 'Invalid Date') { + return 'Unavailable'; + } + const day = date.getDate(); + const month = date.toLocaleString('default', { month: 'long' }); + const year = date.getFullYear(); + return `${day} ${month} ${year}`; +}; +/** + * UserProfile component displays user profile details including an avatar or profile image, name, email, and join date. + * It also provides a button to copy the profile link. + * + * @param props - The properties to be passed into the component. + * @param firstName - The first name of the user. + * @param lastName - The last name of the user. + * @param email - The email address of the user. + * @param image - The URL of the user's profile image. + * @returns The JSX element for the user profile card. + */ const UserProfile: React.FC = ({ firstName, lastName, + createdAt, email, image, }): JSX.Element => { @@ -22,6 +46,7 @@ const UserProfile: React.FC = ({ keyPrefix: 'settings', }); const { t: tCommon } = useTranslation('common'); + return ( <> @@ -41,20 +66,35 @@ const UserProfile: React.FC = ({ )}
    - - {`${firstName}`.charAt(0).toUpperCase() + - `${firstName}`.slice(1)} + + {firstName.length > 10 + ? firstName.slice(0, 5) + '..' + : firstName} + + + + {email.length > 10 + ? email.slice(0, 4) + '..' + email.slice(email.indexOf('@')) + : email} - {email} + - {tCommon('joined')} 1st May, 2021 + {tCommon('joined')} {joinedDate(createdAt)}
    -
    +
    diff --git a/src/components/UserProfileSettings/UserProfileSettings.module.css b/src/components/UserProfileSettings/UserProfileSettings.module.css index 603c5a677d..2c7cc76f57 100644 --- a/src/components/UserProfileSettings/UserProfileSettings.module.css +++ b/src/components/UserProfileSettings/UserProfileSettings.module.css @@ -48,6 +48,7 @@ flex-direction: column; align-items: center; justify-content: space-evenly; + margin-left: 10%; } @media screen and (max-width: 1280px) and (min-width: 992px) { diff --git a/src/components/UsersTableItem/UserTableItem.test.tsx b/src/components/UsersTableItem/UserTableItem.test.tsx index bfa0a31c86..e87b41f7f2 100644 --- a/src/components/UsersTableItem/UserTableItem.test.tsx +++ b/src/components/UsersTableItem/UserTableItem.test.tsx @@ -1,6 +1,6 @@ -import React from 'react'; +import React, { act } from 'react'; import { MockedProvider } from '@apollo/react-testing'; -import { act, fireEvent, render, screen } from '@testing-library/react'; +import { fireEvent, render, screen } from '@testing-library/react'; import { I18nextProvider } from 'react-i18next'; import { toast } from 'react-toastify'; import { StaticMockLink } from 'utils/StaticMockLink'; diff --git a/src/components/UsersTableItem/UsersTableItem.tsx b/src/components/UsersTableItem/UsersTableItem.tsx index 2b35489066..9e94b8a9f5 100644 --- a/src/components/UsersTableItem/UsersTableItem.tsx +++ b/src/components/UsersTableItem/UsersTableItem.tsx @@ -56,7 +56,9 @@ const UsersTableItem = (props: Props): JSX.Element => { }, }); if (data) { - toast.success('Removed User from Organization successfully'); + toast.success( + tCommon('removedSuccessfully', { item: 'User' }) as string, + ); resetAndRefetch(); } } catch (error: unknown) { @@ -77,7 +79,7 @@ const UsersTableItem = (props: Props): JSX.Element => { }, }); if (data) { - toast.success(t('roleUpdated')); + toast.success(t('roleUpdated') as string); resetAndRefetch(); } } catch (error: unknown) { diff --git a/src/components/Venues/VenueCard.tsx b/src/components/Venues/VenueCard.tsx index d4f6f97598..752ac95139 100644 --- a/src/components/Venues/VenueCard.tsx +++ b/src/components/Venues/VenueCard.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { Card, Button } from 'react-bootstrap'; import defaultImg from 'assets/images/defaultImg.png'; -import { ReactComponent as PeopleIcon } from 'assets/svgs/people.svg'; +import PeopleIcon from 'assets/svgs/people.svg?react'; import styles from 'screens/OrganizationVenues/OrganizationVenues.module.css'; import { useTranslation } from 'react-i18next'; import type { InterfaceQueryVenueListItem } from 'utils/interfaces'; @@ -13,13 +13,38 @@ interface InterfaceVenueCardProps { handleDelete: (venueId: string) => void; } +/** + * Represents a card component displaying venue information. + * + * This component renders a card with the venue's image, name, capacity, and description. + * It also provides buttons to edit or delete the venue. + * + * @param venueItem - The venue item to be displayed in the card. + * @param index - The index of the venue item in the list, used for test IDs. + * @param showEditVenueModal - Function to show the edit venue modal, passing the current venue item. + * @param handleDelete - Function to handle the deletion of the venue, passing the venue ID. + * + * @returns JSX.Element - The `VenueCard` component. + * + * @example + * ```tsx + * + * ``` + */ const VenueCard = ({ venueItem, index, showEditVenueModal, handleDelete, }: InterfaceVenueCardProps): JSX.Element => { + // Translation hook for internationalization const { t: tCommon } = useTranslation('common'); + return (
    + {/* Venue image or default image if none provided */} + {/* Venue name with truncation if too long */}
    {venueItem.name.length > 25 ? venueItem.name.slice(0, 25) + '...' : venueItem.name}
    + {/* Venue capacity with icon */}
    Capacity: {venueItem.capacity}
    + {/* Venue description with truncation if too long */} {venueItem.description && venueItem.description.length > 75 ? venueItem.description.slice(0, 75) + '...' : venueItem.description}
    + {/* Edit button */} + {/* Delete button */}
    + {/* Dropdown for filtering members */} + {/* Dropdown for sorting by name */}
    {/* Table */} - {loadingMembers == false && + {loadingMembers === false && membersData.length === 0 && searchByName.length > 0 ? (
    @@ -241,7 +280,7 @@ const Requests = (): JSX.Element => { {tCommon('noResultsFoundFor')} "{searchByName}"
    - ) : loadingMembers == false && membersData.length === 0 ? ( + ) : loadingMembers === false && membersData.length === 0 ? (

    {t('noSpammerFound')}

    diff --git a/src/screens/CommunityProfile/CommunityProfile.test.tsx b/src/screens/CommunityProfile/CommunityProfile.test.tsx index 6f1717bf30..d7e056caa4 100644 --- a/src/screens/CommunityProfile/CommunityProfile.test.tsx +++ b/src/screens/CommunityProfile/CommunityProfile.test.tsx @@ -1,6 +1,6 @@ -import React from 'react'; +import React, { act } from 'react'; import { MockedProvider } from '@apollo/react-testing'; -import { act, render, screen } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import 'jest-localstorage-mock'; import 'jest-location-mock'; @@ -36,7 +36,7 @@ const MOCKS1 = [ socialMediaUrls: { facebook: 'https://socialurl.com', instagram: 'https://socialurl.com', - twitter: 'https://socialurl.com', + X: 'https://socialurl.com', linkedIn: 'https://socialurl.com', gitHub: 'https://socialurl.com', youTube: 'https://socialurl.com', @@ -74,7 +74,7 @@ const MOCKS2 = [ linkedIn: null, reddit: null, slack: null, - twitter: null, + X: null, }, }, }, @@ -115,7 +115,7 @@ const MOCKS3 = [ linkedIn: 'http://sociallink.com', reddit: 'http://sociallink.com', slack: 'http://sociallink.com', - twitter: 'http://sociallink.com', + X: 'http://sociallink.com', }, }, }, @@ -188,7 +188,7 @@ describe('Testing Community Profile Screen', () => { expect(screen.getByPlaceholderText(/Website Link/i)).toBeInTheDocument(); expect(screen.getByTestId(/facebook/i)).toBeInTheDocument(); expect(screen.getByTestId(/instagram/i)).toBeInTheDocument(); - expect(screen.getByTestId(/twitter/i)).toBeInTheDocument(); + expect(screen.getByTestId(/X/i)).toBeInTheDocument(); expect(screen.getByTestId(/linkedIn/i)).toBeInTheDocument(); expect(screen.getByTestId(/github/i)).toBeInTheDocument(); expect(screen.getByTestId(/youtube/i)).toBeInTheDocument(); @@ -213,53 +213,53 @@ describe('Testing Community Profile Screen', () => { , ); - await wait(); + }); + await wait(); - const communityName = screen.getByPlaceholderText(/Community Name/i); - const websiteLink = screen.getByPlaceholderText(/Website Link/i); - const logo = screen.getByTestId(/fileInput/i); - const facebook = screen.getByTestId(/facebook/i); - const instagram = screen.getByTestId(/instagram/i); - const twitter = screen.getByTestId(/twitter/i); - const linkedIn = screen.getByTestId(/linkedIn/i); - const github = screen.getByTestId(/github/i); - const youtube = screen.getByTestId(/youtube/i); - const reddit = screen.getByTestId(/reddit/i); - const slack = screen.getByTestId(/slack/i); - const saveChangesBtn = screen.getByTestId(/saveChangesBtn/i); - const resetChangeBtn = screen.getByTestId(/resetChangesBtn/i); + const communityName = screen.getByPlaceholderText(/Community Name/i); + const websiteLink = screen.getByPlaceholderText(/Website Link/i); + const logo = screen.getByTestId(/fileInput/i); + const facebook = screen.getByTestId(/facebook/i); + const instagram = screen.getByTestId(/instagram/i); + const X = screen.getByTestId(/X/i); + const linkedIn = screen.getByTestId(/linkedIn/i); + const github = screen.getByTestId(/github/i); + const youtube = screen.getByTestId(/youtube/i); + const reddit = screen.getByTestId(/reddit/i); + const slack = screen.getByTestId(/slack/i); + const saveChangesBtn = screen.getByTestId(/saveChangesBtn/i); + const resetChangeBtn = screen.getByTestId(/resetChangesBtn/i); - userEvent.type(communityName, profileVariables.name); - userEvent.type(websiteLink, profileVariables.websiteLink); - userEvent.type(facebook, profileVariables.socialUrl); - userEvent.type(instagram, profileVariables.socialUrl); - userEvent.type(twitter, profileVariables.socialUrl); - userEvent.type(linkedIn, profileVariables.socialUrl); - userEvent.type(github, profileVariables.socialUrl); - userEvent.type(youtube, profileVariables.socialUrl); - userEvent.type(reddit, profileVariables.socialUrl); - userEvent.type(slack, profileVariables.socialUrl); - userEvent.upload(logo, profileVariables.logo); - await wait(); + userEvent.type(communityName, profileVariables.name); + userEvent.type(websiteLink, profileVariables.websiteLink); + userEvent.type(facebook, profileVariables.socialUrl); + userEvent.type(instagram, profileVariables.socialUrl); + userEvent.type(X, profileVariables.socialUrl); + userEvent.type(linkedIn, profileVariables.socialUrl); + userEvent.type(github, profileVariables.socialUrl); + userEvent.type(youtube, profileVariables.socialUrl); + userEvent.type(reddit, profileVariables.socialUrl); + userEvent.type(slack, profileVariables.socialUrl); + userEvent.upload(logo, profileVariables.logo); + await wait(); - expect(communityName).toHaveValue(profileVariables.name); - expect(websiteLink).toHaveValue(profileVariables.websiteLink); - // expect(logo).toBeTruthy(); - expect(facebook).toHaveValue(profileVariables.socialUrl); - expect(instagram).toHaveValue(profileVariables.socialUrl); - expect(twitter).toHaveValue(profileVariables.socialUrl); - expect(linkedIn).toHaveValue(profileVariables.socialUrl); - expect(github).toHaveValue(profileVariables.socialUrl); - expect(youtube).toHaveValue(profileVariables.socialUrl); - expect(reddit).toHaveValue(profileVariables.socialUrl); - expect(slack).toHaveValue(profileVariables.socialUrl); - expect(saveChangesBtn).not.toBeDisabled(); - expect(resetChangeBtn).not.toBeDisabled(); - await wait(); + expect(communityName).toHaveValue(profileVariables.name); + expect(websiteLink).toHaveValue(profileVariables.websiteLink); + // expect(logo).toBeTruthy(); + expect(facebook).toHaveValue(profileVariables.socialUrl); + expect(instagram).toHaveValue(profileVariables.socialUrl); + expect(X).toHaveValue(profileVariables.socialUrl); + expect(linkedIn).toHaveValue(profileVariables.socialUrl); + expect(github).toHaveValue(profileVariables.socialUrl); + expect(youtube).toHaveValue(profileVariables.socialUrl); + expect(reddit).toHaveValue(profileVariables.socialUrl); + expect(slack).toHaveValue(profileVariables.socialUrl); + expect(saveChangesBtn).not.toBeDisabled(); + expect(resetChangeBtn).not.toBeDisabled(); + await wait(); - userEvent.click(saveChangesBtn); - await wait(); - }); + userEvent.click(saveChangesBtn); + await wait(); }); test('If the queried data has some fields null then the input field should be empty', async () => { @@ -276,7 +276,7 @@ describe('Testing Community Profile Screen', () => { expect(screen.getByPlaceholderText(/Website Link/i)).toHaveValue(''); expect(screen.getByTestId(/facebook/i)).toHaveValue(''); expect(screen.getByTestId(/instagram/i)).toHaveValue(''); - expect(screen.getByTestId(/twitter/i)).toHaveValue(''); + expect(screen.getByTestId(/X/i)).toHaveValue(''); expect(screen.getByTestId(/linkedIn/i)).toHaveValue(''); expect(screen.getByTestId(/github/i)).toHaveValue(''); expect(screen.getByTestId(/youtube/i)).toHaveValue(''); @@ -302,7 +302,7 @@ describe('Testing Community Profile Screen', () => { expect(screen.getByPlaceholderText(/Website Link/i)).toHaveValue(''); expect(screen.getByTestId(/facebook/i)).toHaveValue(''); expect(screen.getByTestId(/instagram/i)).toHaveValue(''); - expect(screen.getByTestId(/twitter/i)).toHaveValue(''); + expect(screen.getByTestId(/X/i)).toHaveValue(''); expect(screen.getByTestId(/linkedIn/i)).toHaveValue(''); expect(screen.getByTestId(/github/i)).toHaveValue(''); expect(screen.getByTestId(/youtube/i)).toHaveValue(''); @@ -324,7 +324,7 @@ describe('Testing Community Profile Screen', () => { expect(screen.getByPlaceholderText(/Website Link/i)).toHaveValue(''); expect(screen.getByTestId(/facebook/i)).toHaveValue(''); expect(screen.getByTestId(/instagram/i)).toHaveValue(''); - expect(screen.getByTestId(/twitter/i)).toHaveValue(''); + expect(screen.getByTestId(/X/i)).toHaveValue(''); expect(screen.getByTestId(/linkedIn/i)).toHaveValue(''); expect(screen.getByTestId(/github/i)).toHaveValue(''); expect(screen.getByTestId(/youtube/i)).toHaveValue(''); diff --git a/src/screens/CommunityProfile/CommunityProfile.tsx b/src/screens/CommunityProfile/CommunityProfile.tsx index 96650c1ed8..d96c923eb3 100644 --- a/src/screens/CommunityProfile/CommunityProfile.tsx +++ b/src/screens/CommunityProfile/CommunityProfile.tsx @@ -10,7 +10,7 @@ import { UPDATE_COMMUNITY, RESET_COMMUNITY } from 'GraphQl/Mutations/mutations'; import { FacebookLogo, InstagramLogo, - TwitterLogo, + XLogo, LinkedInLogo, GithubLogo, YoutubeLogo, @@ -20,15 +20,33 @@ import { import convertToBase64 from 'utils/convertToBase64'; import styles from './CommunityProfile.module.css'; import { errorHandler } from 'utils/errorHandler'; +import UpdateSession from '../../components/UpdateSession/UpdateSession'; +/** + * `CommunityProfile` component allows users to view and update their community profile details. + * + * It includes functionalities to: + * - Display current community profile information + * - Update profile details including social media links and logo + * - Reset profile changes to the initial state + * + * @returns JSX.Element - The `CommunityProfile` component. + * + * @example + * ```tsx + * + * ``` + */ const CommunityProfile = (): JSX.Element => { + // Translation hooks for internationalization const { t } = useTranslation('translation', { keyPrefix: 'communityProfile', }); const { t: tCommon } = useTranslation('common'); - document.title = t('title'); + document.title = t('title'); // Set document title + // Define the type for pre-login imagery data type PreLoginImageryDataType = { _id: string; name: string | undefined; @@ -37,7 +55,7 @@ const CommunityProfile = (): JSX.Element => { socialMediaUrls: { facebook: string | undefined; instagram: string | undefined; - twitter: string | undefined; + X: string | undefined; linkedIn: string | undefined; gitHub: string | undefined; youTube: string | undefined; @@ -46,13 +64,14 @@ const CommunityProfile = (): JSX.Element => { }; }; + // State hook for managing profile variables const [profileVariable, setProfileVariable] = React.useState({ name: '', websiteLink: '', logoUrl: '', facebook: '', instagram: '', - twitter: '', + X: '', linkedIn: '', github: '', youtube: '', @@ -60,10 +79,14 @@ const CommunityProfile = (): JSX.Element => { slack: '', }); + // Query to fetch community data const { data, loading } = useQuery(GET_COMMUNITY_DATA); + + // Mutations for updating and resetting community data const [uploadPreLoginImagery] = useMutation(UPDATE_COMMUNITY); const [resetPreLoginImagery] = useMutation(RESET_COMMUNITY); + // Effect to set profile data from fetched data React.useEffect(() => { const preLoginData: PreLoginImageryDataType | undefined = data?.getCommunityData; @@ -74,7 +97,7 @@ const CommunityProfile = (): JSX.Element => { logoUrl: preLoginData.logoUrl ?? '', facebook: preLoginData.socialMediaUrls.facebook ?? '', instagram: preLoginData.socialMediaUrls.instagram ?? '', - twitter: preLoginData.socialMediaUrls.twitter ?? '', + X: preLoginData.socialMediaUrls.X ?? '', linkedIn: preLoginData.socialMediaUrls.linkedIn ?? '', github: preLoginData.socialMediaUrls.gitHub ?? '', youtube: preLoginData.socialMediaUrls.youTube ?? '', @@ -83,6 +106,11 @@ const CommunityProfile = (): JSX.Element => { }); }, [data]); + /** + * Handles change events for form inputs. + * + * @param e - Change event for input elements + */ const handleOnChange = (e: React.ChangeEvent): void => { setProfileVariable({ ...profileVariable, @@ -90,6 +118,11 @@ const CommunityProfile = (): JSX.Element => { }); }; + /** + * Handles form submission to update community profile. + * + * @param e - Form submit event + */ const handleOnSubmit = async ( e: React.FormEvent, ): Promise => { @@ -104,7 +137,7 @@ const CommunityProfile = (): JSX.Element => { socialMediaUrls: { facebook: profileVariable.facebook, instagram: profileVariable.instagram, - twitter: profileVariable.twitter, + X: profileVariable.X, linkedIn: profileVariable.linkedIn, gitHub: profileVariable.github, youTube: profileVariable.youtube, @@ -114,13 +147,16 @@ const CommunityProfile = (): JSX.Element => { }, }, }); - toast.success(t('profileChangedMsg')); + toast.success(t('profileChangedMsg') as string); } catch (error: unknown) { /* istanbul ignore next */ errorHandler(t, error as Error); } }; + /** + * Resets profile data to initial values and performs a reset operation. + */ const resetData = async (): Promise => { const preLoginData: PreLoginImageryDataType | undefined = data?.getCommunityData; @@ -131,7 +167,7 @@ const CommunityProfile = (): JSX.Element => { logoUrl: '', facebook: '', instagram: '', - twitter: '', + X: '', linkedIn: '', github: '', youtube: '', @@ -144,13 +180,18 @@ const CommunityProfile = (): JSX.Element => { resetPreLoginImageryId: preLoginData?._id, }, }); - toast.success(t(`resetData`)); + toast.success(t(`resetData`) as string); } catch (error: unknown) { /* istanbul ignore next */ errorHandler(t, error as Error); } }; + /** + * Determines whether the save and reset buttons should be disabled. + * + * @returns boolean - True if buttons should be disabled, otherwise false + */ const isDisabled = (): boolean => { if ( profileVariable.name == '' && @@ -166,212 +207,220 @@ const CommunityProfile = (): JSX.Element => { if (loading) { ; } + return ( - -
    -
    {t('editProfile')}
    -
    - -
    {t('communityProfileInfo')}
    -
    - - - {t('communityName')} - - - - - - {t('wesiteLink')} - - - - - {t('logo')} - - - {t('social')} -
    - Facebook Logo + <> + +
    +
    {t('editProfile')}
    +
    + +
    {t('communityProfileInfo')}
    + + + + {t('communityName')} + -
    -
    - Instagram Logo + + + + {t('wesiteLink')} + -
    -
    - Twitter Logo + + + {t('logo')} , + ): Promise => { + setProfileVariable((prevInput) => ({ + ...prevInput, + logo: '', + })); + const target = e.target as HTMLInputElement; + const file = target.files?.[0]; + const base64file = file && (await convertToBase64(file)); + setProfileVariable({ + ...profileVariable, + logoUrl: base64file ?? '', + }); + }} + className="mb-3" autoComplete="off" + required /> -
    -
    - LinkedIn Logo - -
    -
    - Github Logo - -
    -
    - Youtube Logo - -
    -
    - Reddit Logo - -
    -
    - Slack Logo - -
    -
    -
    - - -
    -
    -
    -
    + + +
    + + + + + + ); }; diff --git a/src/screens/EventManagement/EventManagement.module.css b/src/screens/EventManagement/EventManagement.module.css deleted file mode 100644 index f7e911887c..0000000000 --- a/src/screens/EventManagement/EventManagement.module.css +++ /dev/null @@ -1,8 +0,0 @@ -.content { - width: 100%; - height: 100%; - min-height: 80vh; - box-sizing: border-box; - background: #ffffff; - border-radius: 1rem; -} diff --git a/src/screens/EventManagement/EventManagement.test.tsx b/src/screens/EventManagement/EventManagement.test.tsx index c51f4eaf12..fb851ec72f 100644 --- a/src/screens/EventManagement/EventManagement.test.tsx +++ b/src/screens/EventManagement/EventManagement.test.tsx @@ -99,6 +99,12 @@ describe('Event Management', () => { const eventActionsTab = screen.getByTestId('eventActionsTab'); expect(eventActionsTab).toBeInTheDocument(); + const eventAgendasButton = screen.getByTestId('eventAgendasBtn'); + userEvent.click(eventAgendasButton); + + const eventAgendasTab = screen.getByTestId('eventAgendasTab'); + expect(eventAgendasTab).toBeInTheDocument(); + const eventStatsButton = screen.getByTestId('eventStatsBtn'); userEvent.click(eventStatsButton); diff --git a/src/screens/EventManagement/EventManagement.tsx b/src/screens/EventManagement/EventManagement.tsx index 8130541616..0101c17736 100644 --- a/src/screens/EventManagement/EventManagement.tsx +++ b/src/screens/EventManagement/EventManagement.tsx @@ -1,29 +1,34 @@ import React, { useState } from 'react'; import Row from 'react-bootstrap/Row'; import Col from 'react-bootstrap/Col'; -import styles from './EventManagement.module.css'; import { Navigate, useNavigate, useParams } from 'react-router-dom'; -import { ReactComponent as AngleLeftIcon } from 'assets/svgs/angleLeft.svg'; -import { ReactComponent as EventDashboardIcon } from 'assets/svgs/eventDashboard.svg'; -import { ReactComponent as EventRegistrantsIcon } from 'assets/svgs/people.svg'; -import { ReactComponent as EventActionsIcon } from 'assets/svgs/settings.svg'; -import { ReactComponent as EventStatisticsIcon } from 'assets/svgs/eventStats.svg'; +import { FaChevronLeft, FaTasks } from 'react-icons/fa'; +import { MdOutlineDashboard } from 'react-icons/md'; +import EventRegistrantsIcon from 'assets/svgs/people.svg?react'; +import { IoMdStats } from 'react-icons/io'; +import EventAgendaItemsIcon from 'assets/svgs/agenda-items.svg?react'; import { useTranslation } from 'react-i18next'; -import { Button } from 'react-bootstrap'; +import { Button, Dropdown } from 'react-bootstrap'; import EventDashboard from 'components/EventManagement/Dashboard/EventDashboard'; -import EventActionItems from 'components/EventManagement/EventActionItems/EventActionItems'; +import OrganizationActionItems from 'screens/OrganizationActionItems/OrganizationActionItems'; +import EventAgendaItems from 'components/EventManagement/EventAgendaItems/EventAgendaItems'; import useLocalStorage from 'utils/useLocalstorage'; import EventAttendance from 'components/EventManagement/EventAttendance/EventAttendance'; import { ReactComponent as EventAttendanceIcon } from 'assets/svgs/Attendance.svg'; import { EventRegistrantsWrapper } from 'components/EventRegistrantsModal/EventRegistrantsWrapper'; +/** + * List of tabs for the event dashboard. + * + * Each tab is associated with an icon and value. + */ const eventDashboardTabs: { value: TabOptions; icon: JSX.Element; }[] = [ { value: 'dashboard', - icon: , + icon: , }, { value: 'registrants', @@ -35,28 +40,56 @@ const eventDashboardTabs: { }, { value: 'eventActions', - icon: , + icon: , + }, + { + value: 'eventAgendas', + icon: , }, { value: 'eventStats', - icon: , + icon: , }, ]; +/** + * Tab options for the event management component. + */ type TabOptions = | 'dashboard' | 'registrants' | 'eventActions' + | 'attendance' + | 'eventAgendas' | 'eventStats' - | 'attendance'; +/** + * `EventManagement` component handles the display and navigation of different event management sections. + * + * It provides a tabbed interface for: + * - Viewing event dashboard + * - Managing event registrants + * - Handling event actions + * - Reviewing event agendas + * - Viewing event statistics + * + * @returns JSX.Element - The `EventManagement` component. + * + * @example + * ```tsx + * + * ``` + */ const EventManagement = (): JSX.Element => { + // Translation hook for internationalization const { t } = useTranslation('translation', { keyPrefix: 'eventManagement', }); + // Custom hook for accessing local storage const { getItem } = useLocalStorage(); + // Determine user role based on local storage const superAdmin = getItem('SuperAdmin'); const adminFor = getItem('AdminFor'); /*istanbul ignore next*/ @@ -66,19 +99,27 @@ const EventManagement = (): JSX.Element => { ? 'ADMIN' : 'USER'; + // Extract event and organization IDs from URL parameters const { eventId, orgId } = useParams(); /*istanbul ignore next*/ if (!eventId || !orgId) { + // Redirect if event ID or organization ID is missing return ; } + // Hook for navigation const navigate = useNavigate(); - const [tab, setTab] = useState('dashboard'); - const handleClick = (value: TabOptions): void => { - setTab(value); - }; + // State hook for managing the currently selected tab + const [tab, setTab] = useState('dashboard'); + /** + * Renders a button for each tab with the appropriate icon and label. + * + * @param value - The tab value + * @param icon - The icon to display for the tab + * @returns JSX.Element - The rendered button component + */ const renderButton = ({ value, icon, @@ -89,26 +130,34 @@ const EventManagement = (): JSX.Element => { const selected = tab === value; const variant = selected ? 'success' : 'light'; const translatedText = t(value); + const className = selected - ? 'px-4' - : 'text-secondary border-secondary-subtle px-4'; + ? 'px-4 d-flex align-items-center shadow' + : 'text-secondary bg-white px-4 d-flex align-items-center rounded shadow'; const props = { variant, className, - key: value, + style: { height: '2.5rem' }, size: 'sm' as 'sm' | 'lg', - onClick: () => handleClick(value), + onClick: () => setTab(value), 'data-testid': `${value}Btn`, }; return ( - ); }; + const handleBack = (): void => { + /*istanbul ignore next*/ + userRole === 'USER' + ? navigate(`/user/events/${orgId}`) + : navigate(`/orgevents/${orgId}`); + }; + return (
    @@ -167,7 +216,47 @@ const EventManagement = (): JSX.Element => { } })()} + + +
    +
    + + {/* Render content based on the selected settings category */} + {(() => { + switch (tab) { + case 'dashboard': + return ( +
    + +
    + ); + case 'registrants': + return ( +
    +

    Event Registrants

    +
    + ); + case 'eventActions': + return ( +
    + +
    + ); + case 'eventAgendas': + return ( +
    + +
    + ); + case 'eventStats': + return ( +
    +

    Event Statistics

    +
    + ); + } + })()}
    ); }; diff --git a/src/screens/ForgotPassword/ForgotPassword.test.tsx b/src/screens/ForgotPassword/ForgotPassword.test.tsx index eb62cb0178..be1b1706f8 100644 --- a/src/screens/ForgotPassword/ForgotPassword.test.tsx +++ b/src/screens/ForgotPassword/ForgotPassword.test.tsx @@ -1,13 +1,13 @@ import React from 'react'; import { MockedProvider } from '@apollo/react-testing'; -import { act, render, screen } from '@testing-library/react'; +import { act, render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import 'jest-localstorage-mock'; import 'jest-location-mock'; import { I18nextProvider } from 'react-i18next'; import { Provider } from 'react-redux'; import { BrowserRouter } from 'react-router-dom'; -import { ToastContainer } from 'react-toastify'; +import { toast, ToastContainer } from 'react-toastify'; import { GENERATE_OTP_MUTATION } from 'GraphQl/Mutations/mutations'; import { store } from 'state/store'; @@ -19,6 +19,14 @@ import useLocalStorage from 'utils/useLocalstorage'; const { setItem, removeItem } = useLocalStorage(); +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + }, +})); + const MOCKS = [ { request: { @@ -159,7 +167,9 @@ describe('Testing Forgot Password screen', () => { ); userEvent.click(screen.getByText('Get OTP')); - await wait(); + await waitFor(() => { + expect(toast.success).toHaveBeenCalled(); + }); }); test('Testing forgot password functionality', async () => { @@ -294,7 +304,6 @@ describe('Testing Forgot Password screen', () => { - @@ -310,11 +319,9 @@ describe('Testing Forgot Password screen', () => { ); userEvent.click(screen.getByText('Get OTP')); - await wait(); - - expect( - await screen.findByText(translations.emailNotRegistered), - ).toBeInTheDocument(); + await waitFor(() => { + expect(toast.warn).toHaveBeenCalledWith(translations.emailNotRegistered); + }); }); test('Testing forgot password functionality, when there is an error except unregistered email and api failure', async () => { @@ -323,7 +330,6 @@ describe('Testing Forgot Password screen', () => { - @@ -331,11 +337,9 @@ describe('Testing Forgot Password screen', () => { , ); userEvent.click(screen.getByText('Get OTP')); - await wait(); - - expect( - await screen.findByText(translations.errorSendingMail), - ).toBeInTheDocument(); + await waitFor(() => { + expect(toast.error).toHaveBeenCalledWith(translations.errorSendingMail); + }); }); test('Testing forgot password functionality, when talawa api failed', async () => { @@ -347,7 +351,6 @@ describe('Testing Forgot Password screen', () => { - @@ -362,11 +365,11 @@ describe('Testing Forgot Password screen', () => { formData.email, ); userEvent.click(screen.getByText('Get OTP')); - await wait(); - - expect( - await screen.findByText(translations.talawaApiUnavailable), - ).toBeInTheDocument(); + await waitFor(() => { + expect(toast.error).toHaveBeenCalledWith( + translations.talawaApiUnavailable, + ); + }); }); test('Testing forgot password functionality, when otp token is not present', async () => { diff --git a/src/screens/ForgotPassword/ForgotPassword.tsx b/src/screens/ForgotPassword/ForgotPassword.tsx index bf1e8c1ee8..663960572b 100644 --- a/src/screens/ForgotPassword/ForgotPassword.tsx +++ b/src/screens/ForgotPassword/ForgotPassword.tsx @@ -8,7 +8,7 @@ import { FORGOT_PASSWORD_MUTATION, GENERATE_OTP_MUTATION, } from 'GraphQl/Mutations/mutations'; -import { ReactComponent as KeyLogo } from 'assets/svgs/key.svg'; +import KeyLogo from 'assets/svgs/key.svg?react'; import ArrowRightAlt from '@mui/icons-material/ArrowRightAlt'; import Loader from 'components/Loader/Loader'; @@ -19,17 +19,35 @@ import { errorHandler } from 'utils/errorHandler'; import styles from './ForgotPassword.module.css'; import useLocalStorage from 'utils/useLocalstorage'; +/** + * `ForgotPassword` component allows users to reset their password. + * + * It provides two stages: + * 1. Entering the registered email to receive an OTP. + * 2. Entering the OTP and new password to reset the password. + * + * @returns JSX.Element - The `ForgotPassword` component. + * + * @example + * ```tsx + * + * ``` + */ const ForgotPassword = (): JSX.Element => { + // Translation hook for internationalization const { t } = useTranslation('translation', { keyPrefix: 'forgotPassword', }); const { t: tCommon } = useTranslation('common'); const { t: tErrors } = useTranslation('errors'); + // Set the page title document.title = t('title'); + // Custom hook for accessing local storage const { getItem, removeItem, setItem } = useLocalStorage(); + // State hooks for form data and UI const [showEnterEmail, setShowEnterEmail] = useState(true); const [registeredEmail, setregisteredEmail] = useState(''); @@ -40,10 +58,13 @@ const ForgotPassword = (): JSX.Element => { confirmNewPassword: '', }); + // GraphQL mutations const [otp, { loading: otpLoading }] = useMutation(GENERATE_OTP_MUTATION); const [forgotPassword, { loading: forgotPasswordLoading }] = useMutation( FORGOT_PASSWORD_MUTATION, ); + + // Check if the user is already logged in const isLoggedIn = getItem('IsLoggedIn'); useEffect(() => { if (isLoggedIn == 'TRUE') { @@ -54,6 +75,11 @@ const ForgotPassword = (): JSX.Element => { }; }, []); + /** + * Handles the form submission for generating OTP. + * + * @param e - The form submit event + */ const getOTP = async (e: ChangeEvent): Promise => { e.preventDefault(); @@ -64,24 +90,25 @@ const ForgotPassword = (): JSX.Element => { }, }); - if (data) { - setItem('otpToken', data.otp.otpToken); - toast.success(t('OTPsent')); - setShowEnterEmail(false); - } + setItem('otpToken', data.otp.otpToken); + toast.success(t('OTPsent')); + setShowEnterEmail(false); } catch (error: unknown) { - if (error instanceof Error) { - if (error.message === 'User not found') { - toast.warn(tErrors('emailNotRegistered')); - } else if (error.message === 'Failed to fetch') { - toast.error(tErrors('talawaApiUnavailable')); - } else { - toast.error(tErrors('errorSendingMail')); - } + if ((error as Error).message === 'User not found') { + toast.warn(tErrors('emailNotRegistered')); + } else if ((error as Error).message === 'Failed to fetch') { + toast.error(tErrors('talawaApiUnavailable')); + } else { + toast.error(tErrors('errorSendingMail')); } } }; + /** + * Handles the form submission for resetting the password. + * + * @param e - The form submit event + */ const submitForgotPassword = async ( e: ChangeEvent, ): Promise => { @@ -89,7 +116,7 @@ const ForgotPassword = (): JSX.Element => { const { userOtp, newPassword, confirmNewPassword } = forgotPassFormData; if (newPassword !== confirmNewPassword) { - toast.error(t('passwordMismatches')); + toast.error(t('passwordMismatches') as string); return; } @@ -110,7 +137,7 @@ const ForgotPassword = (): JSX.Element => { /* istanbul ignore next */ if (data) { - toast.success(t('passwordChanges')); + toast.success(t('passwordChanges') as string); setShowEnterEmail(true); setForgotPassFormData({ userOtp: '', @@ -125,9 +152,11 @@ const ForgotPassword = (): JSX.Element => { } }; + // Show loader while performing OTP or password reset operations if (otpLoading || forgotPasswordLoading) { return ; } + return ( <>
    diff --git a/src/screens/FundCampaignPledge/FundCampaignPledge.module.css b/src/screens/FundCampaignPledge/FundCampaignPledge.module.css index 0e9f3187b7..cdf4476267 100644 --- a/src/screens/FundCampaignPledge/FundCampaignPledge.module.css +++ b/src/screens/FundCampaignPledge/FundCampaignPledge.module.css @@ -56,9 +56,16 @@ flex-direction: column; } +.errorIcon { + transform: scale(1.5); + color: var(--bs-danger); + margin-bottom: 1rem; +} + .btnsContainer { display: flex; - margin: 2.5rem 0 2.5rem 0; + gap: 0.8rem; + margin: 2.2rem 0 0.8rem 0; } .btnsContainer .input { @@ -111,7 +118,13 @@ height: 26px; } -.volunteerContainer { +.imageContainer { + display: flex; + align-items: center; + justify-content: center; +} + +.pledgerContainer { display: flex; align-items: center; justify-content: center; @@ -120,8 +133,141 @@ padding: 0.25rem 0.45rem; border-radius: 0.35rem; background-color: #31bb6b33; + height: 2.2rem; + margin-top: 0.75rem; } .noOutline input { outline: none; } + +.overviewContainer { + display: flex; + gap: 7rem; + width: 100%; + justify-content: space-between; + margin: 1.5rem 0 0 0; + padding: 1.25rem 2rem; + background-color: rgba(255, 255, 255, 0.591); + + box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 4px; + border-radius: 0.5rem; +} + +.titleContainer { + display: flex; + flex-direction: column; + gap: 0.6rem; +} + +.titleContainer h3 { + font-size: 1.75rem; + font-weight: 750; + color: #5e5e5e; + margin-top: 0.2rem; +} + +.titleContainer span { + font-size: 0.9rem; + margin-left: 0.5rem; + font-weight: lighter; + color: #707070; +} + +.raisedAmount { + display: flex; + justify-content: center; + align-items: center; + font-size: 1.25rem; + font-weight: 750; + color: #5e5e5e; +} + +.progressContainer { + display: flex; + flex-direction: column; + gap: 0.5rem; + flex-grow: 1; +} + +.progress { + margin-top: 0.2rem; + display: flex; + flex-direction: column; + gap: 0.3rem; +} + +.endpoints { + display: flex; + position: relative; + font-size: 0.85rem; +} + +.start { + position: absolute; + top: 0px; +} + +.end { + position: absolute; + top: 0px; + right: 0px; +} + +.moreContainer { + display: flex; + align-items: center; +} + +.moreContainer:hover { + text-decoration: underline; + cursor: pointer; +} + +.popup { + z-index: 50; + border-radius: 0.5rem; + font-family: sans-serif; + font-weight: 500; + font-size: 0.875rem; + margin-top: 0.5rem; + padding: 0.75rem; + border: 1px solid #e2e8f0; + background-color: white; + color: #1e293b; + box-shadow: 0 0.5rem 1rem rgb(0 0 0 / 0.15); + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.popupExtra { + max-height: 15rem; + overflow-y: auto; +} + +.toggleGroup { + width: 50%; + min-width: 27.75rem; + margin: 0.5rem 0rem; +} + +.toggleBtn { + padding: 0rem; + height: 30px; + display: flex; + justify-content: center; + align-items: center; +} + +.toggleBtn:hover { + color: #31bb6b !important; +} + +input[type='radio']:checked + label { + background-color: #31bb6a50 !important; +} + +input[type='radio']:checked + label:hover { + color: black !important; +} diff --git a/src/screens/FundCampaignPledge/FundCampaignPledge.test.tsx b/src/screens/FundCampaignPledge/FundCampaignPledge.test.tsx index 7c61a1b48a..3fb5993775 100644 --- a/src/screens/FundCampaignPledge/FundCampaignPledge.test.tsx +++ b/src/screens/FundCampaignPledge/FundCampaignPledge.test.tsx @@ -85,17 +85,6 @@ describe('Testing Campaign Pledge Screen', () => { jest.clearAllMocks(); }); - afterEach(() => { - cleanup(); - }); - - it('should render the Campaign Pledge screen', async () => { - renderFundCampaignPledge(link1); - await waitFor(() => { - expect(screen.getByTestId('searchVolunteer')).toBeInTheDocument(); - }); - }); - it('should redirect to fallback URL if URL params are undefined', async () => { render( @@ -122,6 +111,13 @@ describe('Testing Campaign Pledge Screen', () => { }); }); + it('should render the Campaign Pledge screen', async () => { + renderFundCampaignPledge(link1); + await waitFor(() => { + expect(screen.getByTestId('searchPledger')).toBeInTheDocument(); + }); + }); + it('open and closes Create Pledge modal', async () => { renderFundCampaignPledge(link1); @@ -172,8 +168,8 @@ describe('Testing Campaign Pledge Screen', () => { it('Search the Pledges list by Users', async () => { renderFundCampaignPledge(link1); - const searchVolunteer = await screen.findByTestId('searchVolunteer'); - fireEvent.change(searchVolunteer, { + const searchPledger = await screen.findByTestId('searchPledger'); + fireEvent.change(searchPledger, { target: { value: 'John' }, }); @@ -197,13 +193,97 @@ describe('Testing Campaign Pledge Screen', () => { ); }); + it('check if user image renders', async () => { + renderFundCampaignPledge(link1); + await waitFor(() => { + expect(screen.getByTestId('searchPledger')).toBeInTheDocument(); + }); + + const image = await screen.findByTestId('image1'); + expect(image).toBeInTheDocument(); + expect(image).toHaveAttribute('src', 'img-url'); + }); + + it('should render extraUserDetails in Popup', async () => { + renderFundCampaignPledge(link1); + await waitFor(() => { + expect(screen.getByTestId('searchPledger')).toBeInTheDocument(); + }); + const searchPledger = await screen.findByTestId('searchPledger'); + expect(searchPledger).toBeInTheDocument(); + + fireEvent.click(screen.getByTestId('filter')); + await waitFor(() => { + expect(screen.getByTestId('amount_DESC')).toBeInTheDocument(); + }); + fireEvent.click(screen.getByTestId('amount_DESC')); + + await waitFor(() => { + expect(screen.getByText('John Doe')).toBeInTheDocument(); + expect(screen.queryByText('Jane Doe')).toBeInTheDocument(); + }); + + expect(screen.getByText('John Doe')).toBeInTheDocument(); + expect(screen.getByText('John Doe2')).toBeInTheDocument(); + expect(screen.queryByText('John Doe3')).toBeNull(); + expect(screen.queryByText('John Doe4')).toBeNull(); + + const moreContainer = await screen.findAllByTestId('moreContainer'); + userEvent.click(moreContainer[0]); + + await waitFor(() => { + expect(screen.getByText('John Doe3')).toBeInTheDocument(); + expect(screen.getByText('John Doe4')).toBeInTheDocument(); + expect(screen.getByTestId('extra1')).toBeInTheDocument(); + expect(screen.getByTestId('extra2')).toBeInTheDocument(); + expect(screen.getByTestId('extraAvatar8')).toBeInTheDocument(); + const image = screen.getByTestId('extraImage1'); + expect(image).toBeInTheDocument(); + expect(image).toHaveAttribute('src', 'img-url3'); + }); + + userEvent.click(moreContainer[0]); + await waitFor(() => { + expect(screen.queryByText('John Doe3')).toBeNull(); + expect(screen.queryByText('John Doe4')).toBeNull(); + }); + }); + + it('should render Progress Bar with Raised amount (CONSTANT) & Pledged Amount', async () => { + renderFundCampaignPledge(link1); + await waitFor(() => { + expect(screen.getByTestId('searchPledger')).toBeInTheDocument(); + }); + const raised = screen.getByText('Raised amount'); + const pledged = screen.getByText('Pledged amount'); + expect(pledged).toBeInTheDocument(); + expect(raised).toBeInTheDocument(); + + userEvent.click(raised); + + await waitFor(() => { + expect(screen.getByTestId('progressBar')).toBeInTheDocument(); + expect(screen.getByTestId('progressBar')).toHaveTextContent('$0'); + }); + + userEvent.click(pledged); + + await waitFor(() => { + expect(screen.getByTestId('progressBar')).toBeInTheDocument(); + expect(screen.getByTestId('progressBar')).toHaveTextContent('$300'); + }); + }); + it('Sort the Pledges list by Lowest Amount', async () => { renderFundCampaignPledge(link1); - const searchVolunteer = await screen.findByTestId('searchVolunteer'); - expect(searchVolunteer).toBeInTheDocument(); + const searchPledger = await screen.findByTestId('searchPledger'); + expect(searchPledger).toBeInTheDocument(); fireEvent.click(screen.getByTestId('filter')); + await waitFor(() => { + expect(screen.getByTestId('amount_ASC')).toBeInTheDocument(); + }); fireEvent.click(screen.getByTestId('amount_ASC')); await waitFor(() => { @@ -219,10 +299,13 @@ describe('Testing Campaign Pledge Screen', () => { it('Sort the Pledges list by Highest Amount', async () => { renderFundCampaignPledge(link1); - const searchVolunteer = await screen.findByTestId('searchVolunteer'); - expect(searchVolunteer).toBeInTheDocument(); + const searchPledger = await screen.findByTestId('searchPledger'); + expect(searchPledger).toBeInTheDocument(); fireEvent.click(screen.getByTestId('filter')); + await waitFor(() => { + expect(screen.getByTestId('amount_DESC')).toBeInTheDocument(); + }); fireEvent.click(screen.getByTestId('amount_DESC')); await waitFor(() => { @@ -238,10 +321,13 @@ describe('Testing Campaign Pledge Screen', () => { it('Sort the Pledges list by latest endDate', async () => { renderFundCampaignPledge(link1); - const searchVolunteer = await screen.findByTestId('searchVolunteer'); - expect(searchVolunteer).toBeInTheDocument(); + const searchPledger = await screen.findByTestId('searchPledger'); + expect(searchPledger).toBeInTheDocument(); fireEvent.click(screen.getByTestId('filter')); + await waitFor(() => { + expect(screen.getByTestId('endDate_DESC')).toBeInTheDocument(); + }); fireEvent.click(screen.getByTestId('endDate_DESC')); await waitFor(() => { @@ -257,10 +343,13 @@ describe('Testing Campaign Pledge Screen', () => { it('Sort the Pledges list by earliest endDate', async () => { renderFundCampaignPledge(link1); - const searchVolunteer = await screen.findByTestId('searchVolunteer'); - expect(searchVolunteer).toBeInTheDocument(); + const searchPledger = await screen.findByTestId('searchPledger'); + expect(searchPledger).toBeInTheDocument(); fireEvent.click(screen.getByTestId('filter')); + await waitFor(() => { + expect(screen.getByTestId('endDate_ASC')).toBeInTheDocument(); + }); fireEvent.click(screen.getByTestId('endDate_ASC')); await waitFor(() => { @@ -272,15 +361,4 @@ describe('Testing Campaign Pledge Screen', () => { expect(screen.getAllByTestId('amountCell')[0]).toHaveTextContent('200'); }); }); - - it('check if user image renders', async () => { - renderFundCampaignPledge(link1); - await waitFor(() => { - expect(screen.getByTestId('searchVolunteer')).toBeInTheDocument(); - }); - - const image = await screen.findByAltText('volunteer'); - expect(image).toBeInTheDocument(); - expect(image).toHaveAttribute('src', 'img-url'); - }); }); diff --git a/src/screens/FundCampaignPledge/FundCampaignPledge.tsx b/src/screens/FundCampaignPledge/FundCampaignPledge.tsx index c8d1c95d5b..f7e339dc89 100644 --- a/src/screens/FundCampaignPledge/FundCampaignPledge.tsx +++ b/src/screens/FundCampaignPledge/FundCampaignPledge.tsx @@ -2,6 +2,7 @@ import { useQuery, type ApolloQueryResult } from '@apollo/client'; import { Search, Sort, WarningAmberRounded } from '@mui/icons-material'; import { FUND_CAMPAIGN_PLEDGE } from 'GraphQl/Queries/fundQueries'; import Loader from 'components/Loader/Loader'; +import { Unstable_Popup as BasePopup } from '@mui/base/Unstable_Popup'; import dayjs from 'dayjs'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { Button, Dropdown, Form } from 'react-bootstrap'; @@ -11,37 +12,84 @@ import { currencySymbols } from 'utils/currency'; import styles from './FundCampaignPledge.module.css'; import PledgeDeleteModal from './PledgeDeleteModal'; import PledgeModal from './PledgeModal'; -import { Stack } from '@mui/material'; +import { Breadcrumbs, Link, Stack, Typography } from '@mui/material'; import { DataGrid } from '@mui/x-data-grid'; import Avatar from 'components/Avatar/Avatar'; import type { GridCellParams, GridColDef } from '@mui/x-data-grid'; import type { InterfacePledgeInfo, - InterfacePledgeVolunteer, + InterfacePledger, InterfaceQueryFundCampaignsPledges, } from 'utils/interfaces'; +import ProgressBar from 'react-bootstrap/ProgressBar'; -enum Modal { +interface InterfaceCampaignInfo { + name: string; + goal: number; + startDate: Date; + endDate: Date; + currency: string; +} + +enum ModalState { SAME = 'same', DELETE = 'delete', } +const dataGridStyle = { + '&.MuiDataGrid-root .MuiDataGrid-cell:focus-within': { + outline: 'none !important', + }, + '&.MuiDataGrid-root .MuiDataGrid-columnHeader:focus-within': { + outline: 'none', + }, + '& .MuiDataGrid-row:hover': { + backgroundColor: 'transparent', + }, + '& .MuiDataGrid-row.Mui-hovered': { + backgroundColor: 'transparent', + }, + '& .MuiDataGrid-root': { + borderRadius: '0.5rem', + }, + '& .MuiDataGrid-main': { + borderRadius: '0.5rem', + }, +}; const fundCampaignPledge = (): JSX.Element => { const { t } = useTranslation('translation', { keyPrefix: 'pledges', }); const { t: tCommon } = useTranslation('common'); + const { t: tErrors } = useTranslation('errors'); const { fundCampaignId, orgId } = useParams(); if (!fundCampaignId || !orgId) { return ; } - const [modalState, setModalState] = useState<{ [key in Modal]: boolean }>({ - [Modal.SAME]: false, - [Modal.DELETE]: false, + const [campaignInfo, setCampaignInfo] = useState({ + name: '', + goal: 0, + startDate: new Date(), + endDate: new Date(), + currency: '', }); + const [modalState, setModalState] = useState<{ + [key in ModalState]: boolean; + }>({ + [ModalState.SAME]: false, + [ModalState.DELETE]: false, + }); + + const [anchor, setAnchor] = useState(null); + const [extraUsers, setExtraUsers] = useState([]); + const [progressIndicator, setProgressIndicator] = useState< + 'raised' | 'pledged' + >('pledged'); + const open = Boolean(anchor); + const id = open ? 'simple-popup' : undefined; const [pledgeModalMode, setPledgeModalMode] = useState<'edit' | 'create'>( 'create', ); @@ -59,48 +107,66 @@ const fundCampaignPledge = (): JSX.Element => { refetch: refetchPledge, }: { data?: { - getFundraisingCampaignById: InterfaceQueryFundCampaignsPledges; + getFundraisingCampaigns: InterfaceQueryFundCampaignsPledges[]; }; loading: boolean; error?: Error | undefined; refetch: () => Promise< ApolloQueryResult<{ - getFundraisingCampaignById: InterfaceQueryFundCampaignsPledges; + getFundraisingCampaigns: InterfaceQueryFundCampaignsPledges[]; }> >; } = useQuery(FUND_CAMPAIGN_PLEDGE, { variables: { - id: fundCampaignId, - orderBy: sortBy, + where: { + id: fundCampaignId, + }, + pledgeOrderBy: sortBy, }, }); const endDate = dayjs( - pledgeData?.getFundraisingCampaignById?.endDate, + pledgeData?.getFundraisingCampaigns[0]?.endDate, 'YYYY-MM-DD', ).toDate(); - const pledges = useMemo(() => { - return ( - pledgeData?.getFundraisingCampaignById.pledges.filter((pledge) => { + const { pledges, totalPledged, fundName } = useMemo(() => { + let totalPledged = 0; + const pledges = + pledgeData?.getFundraisingCampaigns[0].pledges.filter((pledge) => { + totalPledged += pledge.amount; const search = searchTerm.toLowerCase(); return pledge.users.some((user) => { const fullName = `${user.firstName} ${user.lastName}`; return fullName.toLowerCase().includes(search); }); - }) ?? [] - ); + }) ?? []; + const fundName = + pledgeData?.getFundraisingCampaigns[0].fundId.name ?? tCommon('Funds'); + return { pledges, totalPledged, fundName }; }, [pledgeData, searchTerm]); + useEffect(() => { + if (pledgeData) { + setCampaignInfo({ + name: pledgeData.getFundraisingCampaigns[0].name, + goal: pledgeData.getFundraisingCampaigns[0].fundingGoal, + startDate: pledgeData.getFundraisingCampaigns[0].startDate, + endDate: pledgeData.getFundraisingCampaigns[0].endDate, + currency: pledgeData.getFundraisingCampaigns[0].currency, + }); + } + }, [pledgeData]); + useEffect(() => { refetchPledge(); }, [sortBy, refetchPledge]); - const openModal = (modal: Modal): void => { + const openModal = (modal: ModalState): void => { setModalState((prevState) => ({ ...prevState, [modal]: true })); }; - const closeModal = (modal: Modal): void => { + const closeModal = (modal: ModalState): void => { setModalState((prevState) => ({ ...prevState, [modal]: false })); }; @@ -108,7 +174,7 @@ const fundCampaignPledge = (): JSX.Element => { (pledge: InterfacePledgeInfo | null, mode: 'edit' | 'create'): void => { setPledge(pledge); setPledgeModalMode(mode); - openModal(Modal.SAME); + openModal(ModalState.SAME); }, [openModal], ); @@ -116,11 +182,19 @@ const fundCampaignPledge = (): JSX.Element => { const handleDeleteClick = useCallback( (pledge: InterfacePledgeInfo): void => { setPledge(pledge); - openModal(Modal.DELETE); + openModal(ModalState.DELETE); }, [openModal], ); + const handleClick = ( + event: React.MouseEvent, + users: InterfacePledger[], + ): void => { + setExtraUsers(users); + setAnchor(anchor ? null : event.currentTarget); + }; + if (pledgeLoading) return ; if (pledgeError) { return ( @@ -128,7 +202,7 @@ const fundCampaignPledge = (): JSX.Element => {
    - Error occured while loading Funds + {tErrors('errorLoading', { entity: 'Pledges' })}
    {pledgeError.message}
    @@ -139,9 +213,9 @@ const fundCampaignPledge = (): JSX.Element => { const columns: GridColDef[] = [ { - field: 'volunteers', - headerName: 'Volunteers', - flex: 2, + field: 'pledgers', + headerName: 'Pledgers', + flex: 3, minWidth: 50, align: 'left', headerAlign: 'center', @@ -150,19 +224,22 @@ const fundCampaignPledge = (): JSX.Element => { renderCell: (params: GridCellParams) => { return (
    - {params.row.users.map( - (user: InterfacePledgeVolunteer, index: number) => ( -
    + {params.row.users + .slice(0, 2) + .map((user: InterfacePledger, index: number) => ( +
    {user.image ? ( volunteer ) : (
    { {user.firstName + ' ' + user.lastName}
    - ), + ))} + {params.row.users.length > 2 && ( +
    handleClick(e, params.row.users.slice(2))} + > + +{params.row.users.length - 2} more... +
    )}
    ); @@ -207,7 +293,7 @@ const fundCampaignPledge = (): JSX.Element => { }, { field: 'amount', - headerName: 'Pledge Amount', + headerName: 'Pledged', flex: 1, minWidth: 100, align: 'center', @@ -230,6 +316,31 @@ const fundCampaignPledge = (): JSX.Element => { ); }, }, + { + field: 'donated', + headerName: 'Donated', + flex: 1, + minWidth: 100, + align: 'center', + headerAlign: 'center', + headerClassName: `${styles.tableHeader}`, + sortable: false, + renderCell: (params: GridCellParams) => { + return ( +
    + { + currencySymbols[ + params.row.currency as keyof typeof currencySymbols + ] + } + 0 +
    + ); + }, + }, { field: 'action', headerName: 'Action', @@ -245,7 +356,7 @@ const fundCampaignPledge = (): JSX.Element => {
    - row._id} - components={{ - NoRowsOverlay: () => ( + slots={{ + noRowsOverlay: () => ( {t('noPledges')} ), }} - sx={{ - '&.MuiDataGrid-root .MuiDataGrid-cell:focus-within': { - outline: 'none !important', - }, - '&.MuiDataGrid-root .MuiDataGrid-columnHeader:focus-within': { - outline: 'none', - }, - '& .MuiDataGrid-row:hover': { - backgroundColor: 'transparent', - }, - '& .MuiDataGrid-row.Mui-hovered': { - backgroundColor: 'transparent', - }, - }} + sx={dataGridStyle} getRowClassName={() => `${styles.rowBackground}`} autoHeight rowHeight={65} @@ -388,26 +571,62 @@ const fundCampaignPledge = (): JSX.Element => { columns={columns} isRowSelectable={() => false} /> - - {/* Update Pledge Modal */} + {/* Update Pledge ModalState */} closeModal(Modal.SAME)} + isOpen={modalState[ModalState.SAME]} + hide={() => closeModal(ModalState.SAME)} campaignId={fundCampaignId} orgId={orgId} pledge={pledge} refetchPledge={refetchPledge} - endDate={pledgeData?.getFundraisingCampaignById.endDate as Date} + endDate={pledgeData?.getFundraisingCampaigns[0].endDate as Date} mode={pledgeModalMode} /> - - {/* Delete Pledge Modal */} + {/* Delete Pledge ModalState */} closeModal(Modal.DELETE)} + isOpen={modalState[ModalState.DELETE]} + hide={() => closeModal(ModalState.DELETE)} pledge={pledge} refetchPledge={refetchPledge} /> + 4 ? styles.popupExtra : ''}`} + > + {extraUsers.map((user: InterfacePledger, index: number) => ( +
    + {user.image ? ( + pledger + ) : ( +
    + +
    + )} + + {user.firstName + ' ' + user.lastName} + +
    + ))} +
    ); }; diff --git a/src/screens/FundCampaignPledge/PledgeDeleteModal.test.tsx b/src/screens/FundCampaignPledge/PledgeDeleteModal.test.tsx index c9d5c5f50e..dbaae76504 100644 --- a/src/screens/FundCampaignPledge/PledgeDeleteModal.test.tsx +++ b/src/screens/FundCampaignPledge/PledgeDeleteModal.test.tsx @@ -23,14 +23,6 @@ jest.mock('react-toastify', () => ({ }, })); -jest.mock('@mui/x-date-pickers/DateTimePicker', () => { - return { - DateTimePicker: jest.requireActual( - '@mui/x-date-pickers/DesktopDateTimePicker', - ).DesktopDateTimePicker, - }; -}); - const link = new StaticMockLink(MOCKS); const link2 = new StaticMockLink(MOCKS_DELETE_PLEDGE_ERROR); const translations = JSON.parse( @@ -57,6 +49,7 @@ const pledgeProps: InterfaceDeletePledgeModal = { }, refetchPledge: jest.fn(), }; + const renderPledgeDeleteModal = ( link: ApolloLink, props: InterfaceDeletePledgeModal, diff --git a/src/screens/FundCampaignPledge/PledgeDeleteModal.tsx b/src/screens/FundCampaignPledge/PledgeDeleteModal.tsx index a16d0df905..288baa16ef 100644 --- a/src/screens/FundCampaignPledge/PledgeDeleteModal.tsx +++ b/src/screens/FundCampaignPledge/PledgeDeleteModal.tsx @@ -13,6 +13,32 @@ export interface InterfaceDeletePledgeModal { pledge: InterfacePledgeInfo | null; refetchPledge: () => void; } + +/** + * A modal dialog for confirming the deletion of a pledge. + * + * @param isOpen - Indicates whether the modal is open. + * @param hide - Function to close the modal. + * @param pledge - The pledge object to be deleted. + * @param refetchPledge - Function to refetch the pledges after deletion. + * + * @returns The rendered modal component. + * + * + * The `PledgeDeleteModal` component displays a confirmation dialog when a user attempts to delete a pledge. + * It allows the user to either confirm or cancel the deletion. + * On confirmation, the `deletePledge` mutation is called to remove the pledge from the database, + * and the `refetchPledge` function is invoked to update the list of pledges. + * A success or error toast notification is shown based on the result of the deletion operation. + * + * The modal includes: + * - A header with a title and a close button. + * - A body with a message asking for confirmation. + * - A footer with "Yes" and "No" buttons to confirm or cancel the deletion. + * + * The `deletePledge` mutation is used to perform the deletion operation. + */ + const PledgeDeleteModal: React.FC = ({ isOpen, hide, @@ -35,7 +61,7 @@ const PledgeDeleteModal: React.FC = ({ }); refetchPledge(); hide(); - toast.success(t('pledgeDeleted')); + toast.success(t('pledgeDeleted') as string); } catch (error: unknown) { toast.error((error as Error).message); } diff --git a/src/screens/FundCampaignPledge/PledgeModal.test.tsx b/src/screens/FundCampaignPledge/PledgeModal.test.tsx index cd1e417f0a..49c0447992 100644 --- a/src/screens/FundCampaignPledge/PledgeModal.test.tsx +++ b/src/screens/FundCampaignPledge/PledgeModal.test.tsx @@ -131,7 +131,7 @@ describe('PledgeModal', () => { await waitFor(() => expect(screen.getByText(translations.editPledge)).toBeInTheDocument(), ); - expect(screen.getByTestId('volunteerSelect')).toHaveTextContent('John Doe'); + expect(screen.getByTestId('pledgerSelect')).toHaveTextContent('John Doe'); expect(screen.getByLabelText('Start Date')).toHaveValue('01/01/2024'); expect(screen.getByLabelText('End Date')).toHaveValue('10/01/2024'); expect(screen.getByLabelText('Currency')).toHaveTextContent('USD ($)'); diff --git a/src/screens/FundCampaignPledge/PledgeModal.tsx b/src/screens/FundCampaignPledge/PledgeModal.tsx index 2fca2379b4..782a051277 100644 --- a/src/screens/FundCampaignPledge/PledgeModal.tsx +++ b/src/screens/FundCampaignPledge/PledgeModal.tsx @@ -6,7 +6,7 @@ import { currencyOptions, currencySymbols } from 'utils/currency'; import type { InterfaceCreatePledge, InterfacePledgeInfo, - InterfacePledgeVolunteer, + InterfacePledger, } from 'utils/interfaces'; import styles from './FundCampaignPledge.module.css'; import React, { useCallback, useEffect, useState } from 'react'; @@ -35,6 +35,40 @@ export interface InterfacePledgeModal { endDate: Date; mode: 'create' | 'edit'; } + +/** + * A modal dialog for creating or editing a pledge. + * + * @param isOpen - Indicates whether the modal is open. + * @param hide - Function to close the modal. + * @param campaignId - The ID of the campaign associated with the pledge. + * @param orgId - The ID of the organization associated with the pledge. + * @param pledge - The pledge object to be edited, or `null` if creating a new pledge. + * @param refetchPledge - Function to refetch the list of pledges after creation or update. + * @param endDate - The end date of the campaign to ensure pledge dates are within this range. + * @param mode - The mode indicating whether the modal is for creating a new pledge or editing an existing one. + * + * @returns The rendered modal component. + * + * The `PledgeModal` component displays a form within a modal dialog for creating or editing a pledge. + * It includes fields for selecting users, entering an amount, choosing a currency, and setting start and end dates for the pledge. + * + * The modal includes: + * - A header with a title indicating the current mode (create or edit) and a close button. + * - A form with: + * - A multi-select dropdown for selecting users to participate in the pledge. + * - Date pickers for selecting the start and end dates of the pledge. + * - A dropdown for selecting the currency of the pledge amount. + * - An input field for entering the pledge amount. + * - A submit button to create or update the pledge. + * + * On form submission, the component either: + * - Calls `updatePledge` mutation to update an existing pledge, or + * - Calls `createPledge` mutation to create a new pledge. + * + * Success or error messages are displayed using toast notifications based on the result of the mutation. + */ + const PledgeModal: React.FC = ({ isOpen, hide, @@ -57,7 +91,7 @@ const PledgeModal: React.FC = ({ pledgeEndDate: new Date(pledge?.endDate ?? new Date()), pledgeStartDate: new Date(pledge?.startDate ?? new Date()), }); - const [volunteers, setVolunteers] = useState([]); + const [pledgers, setPledgers] = useState([]); const [updatePledge] = useMutation(UPDATE_PLEDGE); const [createPledge] = useMutation(CREATE_PlEDGE); @@ -78,7 +112,7 @@ const PledgeModal: React.FC = ({ useEffect(() => { if (memberData) { /*istanbul ignore next*/ - setVolunteers(memberData.organizations[0].members); + setPledgers(memberData.organizations[0].members); } }, [memberData]); @@ -123,7 +157,7 @@ const PledgeModal: React.FC = ({ ...updatedFields, }, }); - toast.success(t('pledgeUpdated')); + toast.success(t('pledgeUpdated') as string); refetchPledge(); hide(); } catch (error: unknown) { @@ -149,7 +183,7 @@ const PledgeModal: React.FC = ({ }, }); - toast.success(t('pledgeCreated')); + toast.success(t('pledgeCreated') as string); refetchPledge(); setFormState({ pledgeUsers: [], @@ -190,31 +224,31 @@ const PledgeModal: React.FC = ({ } className="p-3" > - {/* A Multi-select dropdown enables admin to select more than one volunteer for participating in a pledge */} + {/* A Multi-select dropdown enables admin to select more than one pledger for participating in a pledge */} option._id === value._id} filterSelectedOptions={true} - getOptionLabel={(member: InterfacePledgeVolunteer): string => + getOptionLabel={(member: InterfacePledger): string => `${member.firstName} ${member.lastName}` } onChange={ /*istanbul ignore next*/ - (_, newVolunteers): void => { + (_, newPledgers): void => { setFormState({ ...formState, - pledgeUsers: newVolunteers, + pledgeUsers: newPledgers, }); } } renderInput={(params) => ( - + )} /> diff --git a/src/screens/FundCampaignPledge/PledgesMocks.ts b/src/screens/FundCampaignPledge/PledgesMocks.ts index cf07d1cf28..2a583fa887 100644 --- a/src/screens/FundCampaignPledge/PledgesMocks.ts +++ b/src/screens/FundCampaignPledge/PledgesMocks.ts @@ -6,102 +6,104 @@ import { import { MEMBERS_LIST } from 'GraphQl/Queries/Queries'; import { FUND_CAMPAIGN_PLEDGE } from 'GraphQl/Queries/fundQueries'; -export const MOCKS = [ - { - request: { - query: FUND_CAMPAIGN_PLEDGE, - variables: { - id: 'fundCampaignId', - orderBy: 'endDate_DESC', - }, +const memberList = { + request: { + query: MEMBERS_LIST, + variables: { + id: 'orgId', }, - result: { - data: { - getFundraisingCampaignById: { - startDate: '2024-01-01', - endDate: '2024-08-08', - pledges: [ + }, + result: { + data: { + organizations: [ + { + _id: 'orgId', + members: [ { + createdAt: '2023-04-13T04:53:17.742Z', + email: 'testuser4@example.com', + firstName: 'John', + image: 'img-url', + lastName: 'Doe', + organizationsBlockedBy: [], + __typename: 'User', _id: '1', - amount: 100, - currency: 'USD', - startDate: '2024-01-01', - endDate: '2024-01-10', - users: [ - { - _id: '1', - firstName: 'John', - lastName: 'Doe', - image: 'img-url', - }, - ], }, { + createdAt: '2024-04-13T04:53:17.742Z', + email: 'testuser2@example.com', + firstName: 'Anna', + image: null, + lastName: 'Bradley', + organizationsBlockedBy: [], + __typename: 'User', _id: '2', - amount: 200, - currency: 'USD', - startDate: '2024-01-01', - endDate: '2024-01-09', - users: [ - { - _id: '2', - firstName: 'Jane', - lastName: 'Doe', - image: null, - }, - ], }, ], }, - }, + ], }, }, +}; + +export const MOCKS = [ + memberList, { request: { query: FUND_CAMPAIGN_PLEDGE, variables: { - id: 'fundCampaignId', - orderBy: 'endDate_ASC', + where: { + id: 'fundCampaignId', + }, + pledgeOrderBy: 'endDate_DESC', }, }, result: { data: { - getFundraisingCampaignById: { - startDate: '2024-01-01', - endDate: '2024-08-08', - pledges: [ - { - _id: '2', - amount: 200, - currency: 'USD', - startDate: '2024-01-01', - endDate: '2024-01-09', - users: [ - { - _id: '2', - firstName: 'Jane', - lastName: 'Doe', - image: null, - }, - ], - }, - { - _id: '1', - amount: 100, - currency: 'USD', - startDate: '2024-01-01', - endDate: '2024-01-10', - users: [ - { - _id: '1', - firstName: 'John', - lastName: 'Doe', - image: null, - }, - ], + getFundraisingCampaigns: [ + { + fundId: { + name: 'Fund 1', }, - ], - }, + name: 'Campaign Name', + fundingGoal: 1000, + currency: 'USD', + startDate: '2024-01-01', + endDate: '2034-08-08', + pledges: [ + { + _id: '1', + amount: 100, + currency: 'USD', + startDate: '2024-01-01', + endDate: '2024-01-10', + users: [ + { + _id: '1', + firstName: 'John', + lastName: 'Doe', + image: 'img-url', + }, + ], + }, + { + _id: '2', + amount: 200, + currency: 'USD', + startDate: '2024-01-01', + endDate: '2024-01-09', + users: [ + { + _id: '2', + firstName: 'Jane', + lastName: 'Doe', + image: null, + }, + ], + }, + ], + }, + ], }, }, }, @@ -109,48 +111,58 @@ export const MOCKS = [ request: { query: FUND_CAMPAIGN_PLEDGE, variables: { - id: 'fundCampaignId', - orderBy: 'amount_DESC', + where: { + id: 'fundCampaignId', + }, + pledgeOrderBy: 'endDate_ASC', }, }, result: { data: { - getFundraisingCampaignById: { - startDate: '2024-01-01', - endDate: '2024-08-08', - pledges: [ - { - _id: '2', - amount: 200, - currency: 'USD', - startDate: '2024-01-01', - endDate: '2024-01-09', - users: [ - { - _id: '2', - firstName: 'Jane', - lastName: 'Doe', - image: null, - }, - ], - }, - { - _id: '1', - amount: 100, - currency: 'USD', - startDate: '2024-01-01', - endDate: '2024-01-10', - users: [ - { - _id: '1', - firstName: 'John', - lastName: 'Doe', - image: null, - }, - ], + getFundraisingCampaigns: [ + { + fundId: { + name: 'Fund 1', }, - ], - }, + name: 'Campaign Name', + fundingGoal: 1000, + currency: 'USD', + startDate: '2024-01-01', + endDate: '2024-08-08', + pledges: [ + { + _id: '2', + amount: 200, + currency: 'USD', + startDate: '2024-01-01', + endDate: '2024-01-09', + users: [ + { + _id: '2', + firstName: 'Jane', + lastName: 'Doe', + image: null, + }, + ], + }, + { + _id: '1', + amount: 100, + currency: 'USD', + startDate: '2024-01-01', + endDate: '2024-01-10', + users: [ + { + _id: '1', + firstName: 'John', + lastName: 'Doe', + image: null, + }, + ], + }, + ], + }, + ], }, }, }, @@ -158,247 +170,209 @@ export const MOCKS = [ request: { query: FUND_CAMPAIGN_PLEDGE, variables: { - id: 'fundCampaignId', - orderBy: 'amount_ASC', + where: { + id: 'fundCampaignId', + }, + pledgeOrderBy: 'amount_DESC', }, }, result: { data: { - getFundraisingCampaignById: { - startDate: '2024-01-01', - endDate: '2024-08-08', - pledges: [ - { - _id: '1', - amount: 100, - currency: 'USD', - startDate: '2024-01-01', - endDate: '2024-01-10', - users: [ - { - _id: '1', - firstName: 'John', - lastName: 'Doe', - image: null, - }, - ], - }, - { - _id: '2', - amount: 200, - currency: 'USD', - startDate: '2024-01-01', - endDate: '2024-01-09', - users: [ - { - _id: '2', - firstName: 'Jane', - lastName: 'Doe', - image: null, - }, - ], + getFundraisingCampaigns: [ + { + fundId: { + name: 'Fund 1', }, - ], - }, + name: 'Campaign Name', + fundingGoal: 1000, + currency: 'USD', + startDate: '2024-01-01', + endDate: '2024-08-08', + pledges: [ + { + _id: '2', + amount: 200, + currency: 'USD', + startDate: '2024-01-01', + endDate: '2024-01-09', + users: [ + { + _id: '2', + firstName: 'Jane', + lastName: 'Doe', + image: null, + }, + { + _id: '2', + firstName: 'John', + lastName: 'Doe2', + image: 'img-url2', + }, + { + _id: '3', + firstName: 'John', + lastName: 'Doe3', + image: 'img-url3', + }, + { + _id: '4', + firstName: 'John', + lastName: 'Doe4', + image: 'img-url4', + }, + { + _id: '5', + firstName: 'John', + lastName: 'Doe5', + image: 'img-url5', + }, + { + _id: '6', + firstName: 'John', + lastName: 'Doe6', + image: 'img-url6', + }, + { + _id: '7', + firstName: 'John', + lastName: 'Doe7', + image: 'img-url7', + }, + { + _id: '8', + firstName: 'John', + lastName: 'Doe8', + image: 'img-url8', + }, + { + _id: '9', + firstName: 'John', + lastName: 'Doe9', + image: 'img-url9', + }, + { + _id: '10', + firstName: 'John', + lastName: 'Doe10', + image: null, + }, + ], + }, + { + _id: '1', + amount: 100, + currency: 'USD', + startDate: '2024-01-01', + endDate: '2024-01-10', + users: [ + { + _id: '1', + firstName: 'John', + lastName: 'Doe', + image: null, + }, + ], + }, + ], + }, + ], }, }, }, { request: { - query: DELETE_PLEDGE, + query: FUND_CAMPAIGN_PLEDGE, variables: { - id: '1', + where: { + id: 'fundCampaignId', + }, + pledgeOrderBy: 'amount_ASC', }, }, result: { data: { - removeFundraisingCampaignPledge: { - _id: '1', - }, - }, - }, - }, -]; - -export const MOCKS_FUND_CAMPAIGN_PLEDGE_ERROR = [ - { - request: { - query: FUND_CAMPAIGN_PLEDGE, - variables: { - id: 'fundCampaignId', - orderBy: 'endDate_DESC', + getFundraisingCampaigns: [ + { + fundId: { + name: 'Fund 1', + }, + name: 'Campaign Name', + fundingGoal: 1000, + currency: 'USD', + startDate: '2024-01-01', + endDate: '2024-08-08', + pledges: [ + { + _id: '1', + amount: 100, + currency: 'USD', + startDate: '2024-01-01', + endDate: '2024-01-10', + users: [ + { + _id: '1', + firstName: 'John', + lastName: 'Doe', + image: null, + }, + ], + }, + { + _id: '2', + amount: 200, + currency: 'USD', + startDate: '2024-01-01', + endDate: '2024-01-09', + users: [ + { + _id: '2', + firstName: 'Jane', + lastName: 'Doe', + image: null, + }, + ], + }, + ], + }, + ], }, }, - error: new Error('Error fetching pledges'), }, -]; - -export const MOCKS_CREATE_PLEDGE_ERROR = [ { request: { - query: FUND_CAMPAIGN_PLEDGE, + query: DELETE_PLEDGE, variables: { - id: undefined, + id: '1', }, }, result: { data: { - getFundraisingCampaignById: { - startDate: '2024-01-01', - endDate: '2024-01-01', - pledges: [ - { - _id: '1', - amount: 100, - currency: 'USD', - startDate: '2024-01-01', - endDate: '2024-01-01', - users: [ - { - _id: '1', - firstName: 'John', - }, - ], - }, - { - _id: '2', - amount: 200, - currency: 'USD', - startDate: '2024-03-03', - endDate: '2024-04-03', - users: [ - { - _id: '2', - firstName: 'Jane', - }, - ], - }, - ], + removeFundraisingCampaignPledge: { + _id: '1', }, }, }, }, - { - request: { - query: CREATE_PlEDGE, - variables: { - campaignId: 'campaignId', - amount: 200, - currency: 'USD', - startDate: '2024-01-02', - endDate: '2024-01-02', - userIds: ['1'], - }, - }, - error: new Error('Error creating pledge'), - }, ]; -export const MOCKS_UPDATE_PLEDGE_ERROR = [ +export const MOCKS_FUND_CAMPAIGN_PLEDGE_ERROR = [ + memberList, { request: { query: FUND_CAMPAIGN_PLEDGE, variables: { - id: undefined, - }, - }, - result: { - data: { - getFundraisingCampaignById: { - startDate: '2024-01-01', - endDate: '2024-01-01', - pledges: [ - { - _id: '1', - amount: 100, - currency: 'USD', - startDate: '2024-01-01', - endDate: '2024-01-01', - users: [ - { - _id: '1', - firstName: 'John', - }, - ], - }, - { - _id: '2', - amount: 200, - currency: 'USD', - startDate: '2024-03-03', - endDate: '2024-04-03', - users: [ - { - _id: '2', - firstName: 'Jane', - }, - ], - }, - ], + where: { + id: 'fundCampaignId', }, + pledgeOrderBy: 'endDate_DESC', }, }, - }, - { - request: { - query: UPDATE_PLEDGE, - variables: { - id: '1', - amount: 200, - currency: 'USD', - startDate: '2024-03-10', - endDate: '2024-03-10', - }, - }, - error: new Error('Error updating pledge'), + error: new Error('Error fetching pledges'), }, ]; export const MOCKS_DELETE_PLEDGE_ERROR = [ - { - request: { - query: FUND_CAMPAIGN_PLEDGE, - variables: { - id: undefined, - }, - }, - result: { - data: { - getFundraisingCampaignById: { - startDate: '2024-01-01', - endDate: '2024-01-01', - pledges: [ - { - _id: '1', - amount: 100, - currency: 'USD', - startDate: '2024-01-01', - endDate: '2024-01-01', - users: [ - { - _id: '1', - firstName: 'John', - }, - ], - }, - { - _id: '2', - amount: 200, - currency: 'USD', - startDate: '2024-03-03', - endDate: '2024-04-03', - users: [ - { - _id: '2', - firstName: 'Jane', - }, - ], - }, - ], - }, - }, - }, - }, + memberList, { request: { query: DELETE_PLEDGE, @@ -411,66 +385,39 @@ export const MOCKS_DELETE_PLEDGE_ERROR = [ ]; export const EMPTY_MOCKS = [ + memberList, { request: { query: FUND_CAMPAIGN_PLEDGE, variables: { - id: 'fundCampaignId', - orderBy: 'endDate_DESC', - }, - }, - result: { - data: { - getFundraisingCampaignById: { - startDate: '2024-01-01', - endDate: '2024-01-01', - pledges: [], + where: { + id: 'fundCampaignId', }, - }, - }, - }, -]; - -export const PLEDGE_MODAL_MOCKS = [ - { - request: { - query: MEMBERS_LIST, - variables: { - id: 'orgId', + pledgeOrderBy: 'endDate_DESC', }, }, result: { data: { - organizations: [ + getFundraisingCampaigns: [ { - _id: 'orgId', - members: [ - { - createdAt: '2023-04-13T04:53:17.742Z', - email: 'testuser4@example.com', - firstName: 'John', - image: 'img-url', - lastName: 'Doe', - organizationsBlockedBy: [], - __typename: 'User', - _id: '1', - }, - { - createdAt: '2024-04-13T04:53:17.742Z', - email: 'testuser2@example.com', - firstName: 'Anna', - image: null, - lastName: 'Bradley', - organizationsBlockedBy: [], - __typename: 'User', - _id: '2', - }, - ], + fundId: { + name: 'Fund 1', + }, + name: 'Campaign Name', + fundingGoal: 1000, + currency: 'USD', + startDate: '2024-01-01', + endDate: '2024-01-01', + pledges: [], }, ], }, }, }, +]; + +export const PLEDGE_MODAL_MOCKS = [ + memberList, { request: { query: UPDATE_PLEDGE, diff --git a/src/screens/LoginPage/LoginPage.test.tsx b/src/screens/LoginPage/LoginPage.test.tsx index a61f8adb2e..3733a454dd 100644 --- a/src/screens/LoginPage/LoginPage.test.tsx +++ b/src/screens/LoginPage/LoginPage.test.tsx @@ -1,6 +1,6 @@ -import React from 'react'; +import React, { act } from 'react'; import { MockedProvider } from '@apollo/react-testing'; -import { act, render, screen, fireEvent, within } from '@testing-library/react'; +import { render, screen, fireEvent, within } from '@testing-library/react'; import { Provider } from 'react-redux'; import { BrowserRouter } from 'react-router-dom'; import userEvent from '@testing-library/user-event'; @@ -114,7 +114,7 @@ const MOCKS2 = [ linkedIn: 'http://url.com', reddit: 'http://url.com', slack: 'http://url.com', - twitter: null, + X: null, __typename: 'SocialMediaUrls', }, }, diff --git a/src/screens/LoginPage/LoginPage.tsx b/src/screens/LoginPage/LoginPage.tsx index 90b2b28b49..2ed1e71c13 100644 --- a/src/screens/LoginPage/LoginPage.tsx +++ b/src/screens/LoginPage/LoginPage.tsx @@ -23,10 +23,9 @@ import { SIGNUP_MUTATION, } from 'GraphQl/Mutations/mutations'; import { GET_COMMUNITY_DATA, ORGANIZATION_LIST } from 'GraphQl/Queries/Queries'; -import { ReactComponent as PalisadoesLogo } from 'assets/svgs/palisadoes.svg'; -import { ReactComponent as TalawaLogo } from 'assets/svgs/talawa.svg'; +import PalisadoesLogo from 'assets/svgs/palisadoes.svg?react'; +import TalawaLogo from 'assets/svgs/talawa.svg?react'; import ChangeLanguageDropDown from 'components/ChangeLanguageDropdown/ChangeLanguageDropDown'; -import Loader from 'components/Loader/Loader'; import LoginPortalToggle from 'components/LoginPortalToggle/LoginPortalToggle'; import { errorHandler } from 'utils/errorHandler'; import useLocalStorage from 'utils/useLocalstorage'; @@ -34,6 +33,15 @@ import { socialMediaLinks } from '../../constants'; import styles from './LoginPage.module.css'; import type { InterfaceQueryOrganizationListObject } from 'utils/interfaces'; import { Autocomplete, TextField } from '@mui/material'; +import useSession from 'utils/useSession'; +import i18n from 'utils/i18n'; + +/** + * LoginPage component is used to render the login page of the application where user can login or register + * to the application using email and password. The component also provides the functionality to switch between login and + * register form. + * + */ const loginPage = (): JSX.Element => { const { t } = useTranslation('translation', { keyPrefix: 'loginPage' }); @@ -56,7 +64,6 @@ const loginPage = (): JSX.Element => { const [recaptchaToken, setRecaptchaToken] = useState(null); const [showTab, setShowTab] = useState<'LOGIN' | 'REGISTER'>('LOGIN'); const [role, setRole] = useState<'admin' | 'user'>('admin'); - const [componentLoader, setComponentLoader] = useState(true); const [isInputFocused, setIsInputFocused] = useState(false); const [signformState, setSignFormState] = useState({ signfirstName: '', @@ -105,25 +112,24 @@ const loginPage = (): JSX.Element => { const isLoggedIn = getItem('IsLoggedIn'); if (isLoggedIn == 'TRUE') { navigate(getItem('userId') !== null ? '/user/organizations' : '/orglist'); + extendSession(); } - setComponentLoader(false); }, []); const togglePassword = (): void => setShowPassword(!showPassword); const toggleConfirmPassword = (): void => setShowConfirmPassword(!showConfirmPassword); - const { data, loading, refetch } = useQuery(GET_COMMUNITY_DATA); + const { data, refetch } = useQuery(GET_COMMUNITY_DATA); useEffect(() => { // refetching the data if the pre-login data updates refetch(); }, [data]); const [login, { loading: loginLoading }] = useMutation(LOGIN_MUTATION); const [signup, { loading: signinLoading }] = useMutation(SIGNUP_MUTATION); - const [recaptcha, { loading: recaptchaLoading }] = - useMutation(RECAPTCHA_MUTATION); + const [recaptcha] = useMutation(RECAPTCHA_MUTATION); const { data: orgData } = useQuery(ORGANIZATION_LIST); - + const { startSession, extendSession } = useSession(); useEffect(() => { if (orgData) { const options = orgData.organizations.map( @@ -172,7 +178,7 @@ const loginPage = (): JSX.Element => { return data.recaptcha; } catch (error) { /* istanbul ignore next */ - toast.error(t('captchaError')); + toast.error(t('captchaError') as string); } }; @@ -195,7 +201,7 @@ const loginPage = (): JSX.Element => { const isVerified = await verifyRecaptcha(recaptchaToken); /* istanbul ignore next */ if (!isVerified) { - toast.error(t('Please_check_the_captcha')); + toast.error(t('Please_check_the_captcha') as string); return; } const isValidatedString = (value: string): boolean => @@ -236,7 +242,9 @@ const loginPage = (): JSX.Element => { /* istanbul ignore next */ if (signUpData) { toast.success( - t(role === 'admin' ? 'successfullyRegistered' : 'afterRegister'), + t( + role === 'admin' ? 'successfullyRegistered' : 'afterRegister', + ) as string, ); setShowTab('LOGIN'); setSignFormState({ @@ -253,20 +261,20 @@ const loginPage = (): JSX.Element => { errorHandler(t, error); } } else { - toast.warn(t('passwordMismatches')); + toast.warn(t('passwordMismatches') as string); } } else { if (!isValidatedString(signfirstName)) { - toast.warn(t('firstName_invalid')); + toast.warn(t('firstName_invalid') as string); } if (!isValidatedString(signlastName)) { - toast.warn(t('lastName_invalid')); + toast.warn(t('lastName_invalid') as string); } if (!validatePassword(signPassword)) { - toast.warn(t('password_invalid')); + toast.warn(t('password_invalid') as string); } if (signEmail.length < 8) { - toast.warn(t('email_invalid')); + toast.warn(t('email_invalid') as string); } } }; @@ -276,7 +284,7 @@ const loginPage = (): JSX.Element => { const isVerified = await verifyRecaptcha(recaptchaToken); /* istanbul ignore next */ if (!isVerified) { - toast.error(t('Please_check_the_captcha')); + toast.error(t('Please_check_the_captcha') as string); return; } @@ -290,13 +298,14 @@ const loginPage = (): JSX.Element => { /* istanbul ignore next */ if (loginData) { + i18n.changeLanguage(loginData.login.appUserProfile.appLanguageCode); const { login } = loginData; const { user, appUserProfile } = login; const isAdmin: boolean = appUserProfile.isSuperAdmin || appUserProfile.adminFor.length !== 0; if (role === 'admin' && !isAdmin) { - toast.warn(tErrors('notAuthorised')); + toast.warn(tErrors('notAuthorised') as string); return; } const loggedInUserId = user._id; @@ -319,8 +328,9 @@ const loginPage = (): JSX.Element => { } navigate(role === 'admin' ? '/orglist' : '/user/organizations'); + startSession(); } else { - toast.warn(tErrors('notFound')); + toast.warn(tErrors('notFound') as string); } } catch (error) { /* istanbul ignore next */ @@ -328,15 +338,6 @@ const loginPage = (): JSX.Element => { } }; - if ( - componentLoader || - loginLoading || - signinLoading || - recaptchaLoading || - loading - ) { - return ; - } const socialIconsList = socialMediaLinks.map(({ href, logo, tag }, index) => data?.getCommunityData ? ( data.getCommunityData?.socialMediaUrls?.[tag] && ( @@ -427,6 +428,7 @@ const loginPage = (): JSX.Element => {
    { password: e.target.value, }); }} + disabled={loginLoading} autoComplete="current-password" /> diff --git a/src/screens/ManageTag/ManageTag.module.css b/src/screens/ManageTag/ManageTag.module.css new file mode 100644 index 0000000000..db1886099a --- /dev/null +++ b/src/screens/ManageTag/ManageTag.module.css @@ -0,0 +1,119 @@ +.btnsContainer { + display: flex; + margin: 2rem 0; +} + +.btnsContainer .btnsBlock { + display: flex; + width: max-content; +} + +.btnsContainer .btnsBlock button { + margin-left: 1rem; + display: flex; + justify-content: center; + align-items: center; +} + +.btnsContainer .input { + flex: 1; + position: relative; + max-width: 60%; + justify-content: space-between; +} + +.btnsContainer input { + outline: 1px solid var(--bs-gray-400); +} + +.btnsContainer .input button { + width: 52px; +} + +@media (max-width: 1020px) { + .btnsContainer { + flex-direction: column; + margin: 1.5rem 0; + } + + .btnsContainer .btnsBlock { + margin: 1.5rem 0 0 0; + justify-content: space-between; + } + + .btnsContainer .btnsBlock button { + margin: 0; + } + + .btnsContainer .btnsBlock div button { + margin-right: 1.5rem; + } +} + +/* For mobile devices */ + +@media (max-width: 520px) { + .btnsContainer { + margin-bottom: 0; + } + + .btnsContainer .btnsBlock { + display: block; + margin-top: 1rem; + margin-right: 0; + } + + .btnsContainer .btnsBlock div { + flex: 1; + } + + .btnsContainer .btnsBlock div[title='Sort organizations'] { + margin-right: 0.5rem; + } + + .btnsContainer .btnsBlock button { + margin-bottom: 1rem; + margin-right: 0; + width: 100%; + } +} + +.errorContainer { + min-height: 100vh; +} + +.errorMessage { + margin-top: 25%; + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; +} + +.errorIcon { + transform: scale(1.5); + color: var(--bs-danger); + margin-bottom: 1rem; +} + +.tableHeader { + background-color: var(--bs-primary); + color: var(--bs-white); + font-size: 1rem; +} + +.rowBackground { + background-color: var(--bs-white); + max-height: 120px; +} + +.tagsBreadCrumbs { + color: var(--bs-gray); + cursor: pointer; +} + +.tagsBreadCrumbs:hover { + color: var(--bs-blue); + font-weight: 600; + text-decoration: underline; +} diff --git a/src/screens/ManageTag/ManageTag.test.tsx b/src/screens/ManageTag/ManageTag.test.tsx new file mode 100644 index 0000000000..5de5e97c88 --- /dev/null +++ b/src/screens/ManageTag/ManageTag.test.tsx @@ -0,0 +1,440 @@ +import React from 'react'; +import { MockedProvider } from '@apollo/react-testing'; +import type { RenderResult } from '@testing-library/react'; +import { + act, + cleanup, + render, + screen, + waitFor, + waitForElementToBeRemoved, +} from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import 'jest-location-mock'; +import { I18nextProvider } from 'react-i18next'; +import { Provider } from 'react-redux'; +import { MemoryRouter, Route, Routes } from 'react-router-dom'; +import { toast } from 'react-toastify'; +import { store } from 'state/store'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import i18n from 'utils/i18nForTest'; +import ManageTag from './ManageTag'; +import { + MOCKS, + MOCKS_ERROR_ASSIGNED_MEMBERS, + MOCKS_ERROR_TAG_ANCESTORS, +} from './ManageTagMocks'; +import { InMemoryCache, type ApolloLink } from '@apollo/client'; + +const translations = { + ...JSON.parse( + JSON.stringify(i18n.getDataByLanguage('en')?.translation.manageTag ?? {}), + ), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.common ?? {})), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.errors ?? {})), +}; + +const link = new StaticMockLink(MOCKS, true); +const link2 = new StaticMockLink(MOCKS_ERROR_ASSIGNED_MEMBERS, true); +const link3 = new StaticMockLink(MOCKS_ERROR_TAG_ANCESTORS, true); + +async function wait(ms = 500): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + info: jest.fn(), + error: jest.fn(), + }, +})); + +const cache = new InMemoryCache({ + typePolicies: { + Query: { + fields: { + getUserTag: { + keyArgs: false, + merge(_, incoming) { + return incoming; + }, + }, + }, + }, + }, +}); + +const renderManageTag = (link: ApolloLink): RenderResult => { + return render( + + + + + +
    } + /> + } + /> +
    } + /> +
    } + /> + + + + + , + ); +}; + +describe('Manage Tag Page', () => { + beforeEach(() => { + jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: 'orgId' }), + })); + cache.reset(); + }); + + afterEach(() => { + jest.clearAllMocks(); + cleanup(); + }); + + test('Component loads correctly', async () => { + const { getByText } = renderManageTag(link); + + await wait(); + + await waitFor(() => { + expect(getByText(translations.addPeopleToTag)).toBeInTheDocument(); + }); + }); + + test('renders error component on unsuccessful userTag assigned members query', async () => { + const { queryByText } = renderManageTag(link2); + + await wait(); + + await waitFor(() => { + expect(queryByText(translations.addPeopleToTag)).not.toBeInTheDocument(); + }); + }); + + test('renders error component on unsuccessful userTag ancestors query', async () => { + const { queryByText } = renderManageTag(link3); + + await wait(); + + await waitFor(() => { + expect(queryByText(translations.addPeopleToTag)).not.toBeInTheDocument(); + }); + }); + + test('opens and closes the add people to tag modal', async () => { + renderManageTag(link); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('addPeopleToTagBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('addPeopleToTagBtn')); + + await waitFor(() => { + return expect( + screen.findByTestId('closeAddPeopleToTagModal'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('closeAddPeopleToTagModal')); + + await waitForElementToBeRemoved(() => + screen.queryByTestId('closeAddPeopleToTagModal'), + ); + }); + + test('opens and closes the unassign tag modal', async () => { + renderManageTag(link); + + await wait(); + + await waitFor(() => { + expect(screen.getAllByTestId('unassignTagBtn')[0]).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('unassignTagBtn')[0]); + + await waitFor(() => { + return expect( + screen.findByTestId('unassignTagModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('unassignTagModalCloseBtn')); + + await waitForElementToBeRemoved(() => + screen.queryByTestId('unassignTagModalCloseBtn'), + ); + }); + + test('opens and closes the assignToTags modal', async () => { + renderManageTag(link); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('assignToTags')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('assignToTags')); + + await waitFor(() => { + return expect( + screen.findByTestId('closeTagActionsModalBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('closeTagActionsModalBtn')); + + await waitForElementToBeRemoved(() => + screen.queryByTestId('closeTagActionsModalBtn'), + ); + }); + + test('opens and closes the removeFromTags modal', async () => { + renderManageTag(link); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('removeFromTags')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('removeFromTags')); + + await waitFor(() => { + return expect( + screen.findByTestId('closeTagActionsModalBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('closeTagActionsModalBtn')); + + await waitForElementToBeRemoved(() => + screen.queryByTestId('closeTagActionsModalBtn'), + ); + }); + + test('opens and closes the edit tag modal', async () => { + renderManageTag(link); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('editTag')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('editTag')); + + await waitFor(() => { + return expect( + screen.findByTestId('closeEditTagModalBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('closeEditTagModalBtn')); + + await waitForElementToBeRemoved(() => + screen.queryByTestId('closeEditTagModalBtn'), + ); + }); + + test('opens and closes the remove tag modal', async () => { + renderManageTag(link); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('removeTag')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('removeTag')); + + await waitFor(() => { + return expect( + screen.findByTestId('removeUserTagModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('removeUserTagModalCloseBtn')); + + await waitForElementToBeRemoved(() => + screen.queryByTestId('removeUserTagModalCloseBtn'), + ); + }); + + test("navigates to the member's profile after clicking the view option", async () => { + renderManageTag(link); + + await wait(); + + await waitFor(() => { + expect(screen.getAllByTestId('viewProfileBtn')[0]).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('viewProfileBtn')[0]); + + await waitFor(() => { + expect(screen.getByTestId('memberProfileScreen')).toBeInTheDocument(); + }); + }); + + test('navigates to the subTags screen after clicking the subTags option', async () => { + renderManageTag(link); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('subTagsBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('subTagsBtn')); + + await waitFor(() => { + expect(screen.getByTestId('subTagsScreen')).toBeInTheDocument(); + }); + }); + + test('navigates to the manageTag screen after clicking a tag in the breadcrumbs', async () => { + renderManageTag(link); + + await wait(); + + await waitFor(() => { + expect( + screen.getAllByTestId('redirectToManageTag')[0], + ).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('redirectToManageTag')[0]); + + await waitFor(() => { + expect(screen.getByTestId('addPeopleToTagBtn')).toBeInTheDocument(); + }); + }); + + test('navigates to organization tags screen screen after clicking tha all tags option in the breadcrumbs', async () => { + renderManageTag(link); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('allTagsBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('allTagsBtn')); + + await waitFor(() => { + expect(screen.getByTestId('organizationTagsScreen')).toBeInTheDocument(); + }); + }); + + test('paginates between different pages', async () => { + renderManageTag(link); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('nextPagBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('nextPagBtn')); + + await waitFor(() => { + expect(screen.getAllByTestId('memberName')[0]).toHaveTextContent( + 'member 6', + ); + }); + + await waitFor(() => { + expect(screen.getByTestId('previousPageBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('previousPageBtn')); + + await waitFor(() => { + expect(screen.getAllByTestId('memberName')[0]).toHaveTextContent( + 'member 1', + ); + }); + }); + + test('unassigns a tag from a member', async () => { + renderManageTag(link); + + await wait(); + + await waitFor(() => { + expect(screen.getAllByTestId('unassignTagBtn')[0]).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('unassignTagBtn')[0]); + + userEvent.click(screen.getByTestId('unassignTagModalSubmitBtn')); + + await waitFor(() => { + expect(toast.success).toHaveBeenCalledWith( + translations.successfullyUnassigned, + ); + }); + }); + + test('successfully edits the tag name', async () => { + renderManageTag(link); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('editTag')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('editTag')); + + userEvent.click(screen.getByTestId('editTagSubmitBtn')); + + await waitFor(() => { + expect(toast.info).toHaveBeenCalledWith(translations.changeNameToEdit); + }); + + const tagNameInput = screen.getByTestId('tagNameInput'); + await userEvent.clear(tagNameInput); + await userEvent.type(tagNameInput, 'tag 1 edited'); + expect(tagNameInput).toHaveValue('tag 1 edited'); + + userEvent.click(screen.getByTestId('editTagSubmitBtn')); + + await waitFor(() => { + expect(toast.success).toHaveBeenCalledWith( + translations.tagUpdationSuccess, + ); + }); + }); + + test('successfully removes the tag and redirects to orgTags page', async () => { + renderManageTag(link); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('removeTag')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('removeTag')); + + userEvent.click(screen.getByTestId('removeUserTagSubmitBtn')); + + await waitFor(() => { + expect(toast.success).toHaveBeenCalledWith( + translations.tagRemovalSuccess, + ); + }); + + await waitFor(() => { + expect(screen.getByTestId('organizationTagsScreen')).toBeInTheDocument(); + }); + }); +}); diff --git a/src/screens/ManageTag/ManageTag.tsx b/src/screens/ManageTag/ManageTag.tsx new file mode 100644 index 0000000000..884b402a7c --- /dev/null +++ b/src/screens/ManageTag/ManageTag.tsx @@ -0,0 +1,699 @@ +import type { FormEvent } from 'react'; +import React, { useEffect, useState } from 'react'; +import { useMutation, useQuery, type ApolloError } from '@apollo/client'; +import { Search, WarningAmberRounded } from '@mui/icons-material'; +import SortIcon from '@mui/icons-material/Sort'; +import Loader from 'components/Loader/Loader'; +import IconComponent from 'components/IconComponent/IconComponent'; +import { useNavigate, useParams, Link } from 'react-router-dom'; +import { Col, Form } from 'react-bootstrap'; +import Button from 'react-bootstrap/Button'; +import Dropdown from 'react-bootstrap/Dropdown'; +import Modal from 'react-bootstrap/Modal'; +import Row from 'react-bootstrap/Row'; +import { useTranslation } from 'react-i18next'; +import { toast } from 'react-toastify'; +import type { InterfaceQueryUserTagsAssignedMembers } from 'utils/interfaces'; +import styles from './ManageTag.module.css'; +import { DataGrid } from '@mui/x-data-grid'; +import type { TagActionType } from 'utils/organizationTagsUtils'; +import { dataGridStyle } from 'utils/organizationTagsUtils'; +import type { GridCellParams, GridColDef } from '@mui/x-data-grid'; +import { Stack } from '@mui/material'; +import { + REMOVE_USER_TAG, + UNASSIGN_USER_TAG, + UPDATE_USER_TAG, +} from 'GraphQl/Mutations/TagMutations'; +import { + USER_TAG_ANCESTORS, + USER_TAGS_ASSIGNED_MEMBERS, +} from 'GraphQl/Queries/userTagQueries'; +import AddPeopleToTag from 'components/AddPeopleToTag/AddPeopleToTag'; +import TagActions from 'components/TagActions/TagActions'; + +/** + * Component that renders the Manage Tag screen when the app navigates to '/orgtags/:orgId/managetag/:tagId'. + * + * This component does not accept any props and is responsible for displaying + * the content associated with the corresponding route. + */ + +function ManageTag(): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'manageTag', + }); + const { t: tCommon } = useTranslation('common'); + + const [unassignTagModalIsOpen, setUnassignTagModalIsOpen] = useState(false); + + const [addPeopleToTagModalIsOpen, setAddPeopleToTagModalIsOpen] = + useState(false); + const [assignToTagsModalIsOpen, setAssignToTagsModalIsOpen] = useState(false); + + const [editTagModalIsOpen, setEditTagModalIsOpen] = useState(false); + const [removeTagModalIsOpen, setRemoveTagModalIsOpen] = useState(false); + + const { orgId, tagId: currentTagId } = useParams(); + const navigate = useNavigate(); + const [after, setAfter] = useState(null); + const [before, setBefore] = useState(null); + const [first, setFirst] = useState(5); + const [last, setLast] = useState(null); + + const [unassignUserId, setUnassignUserId] = useState(null); + + // a state to specify whether we're assigning to tags or removing from tags + const [tagActionType, setTagActionType] = + useState('assignToTags'); + + const toggleRemoveUserTagModal = (): void => { + setRemoveTagModalIsOpen(!removeTagModalIsOpen); + }; + + const showAddPeopleToTagModal = (): void => { + setAddPeopleToTagModalIsOpen(true); + }; + + const hideAddPeopleToTagModal = (): void => { + setAddPeopleToTagModalIsOpen(false); + }; + + const showAssignToTagsModal = (): void => { + setAssignToTagsModalIsOpen(true); + }; + + const hideAssignToTagsModal = (): void => { + setAssignToTagsModalIsOpen(false); + }; + + const showEditTagModal = (): void => { + setEditTagModalIsOpen(true); + }; + + const hideEditTagModal = (): void => { + setEditTagModalIsOpen(false); + }; + + const { + data: userTagAssignedMembersData, + loading: userTagAssignedMembersLoading, + error: userTagAssignedMembersError, + refetch: userTagAssignedMembersRefetch, + }: { + data?: { + getUserTag: InterfaceQueryUserTagsAssignedMembers; + }; + loading: boolean; + error?: ApolloError; + refetch: () => void; + } = useQuery(USER_TAGS_ASSIGNED_MEMBERS, { + variables: { + id: currentTagId, + after: after, + before: before, + first: first, + last: last, + }, + }); + + const { + data: orgUserTagAncestorsData, + loading: orgUserTagsAncestorsLoading, + refetch: orgUserTagsAncestorsRefetch, + error: orgUserTagsAncestorsError, + }: { + data?: { + getUserTagAncestors: { + _id: string; + name: string; + }[]; + }; + loading: boolean; + error?: ApolloError; + refetch: () => void; + } = useQuery(USER_TAG_ANCESTORS, { + variables: { + id: currentTagId, + }, + }); + + const [unassignUserTag] = useMutation(UNASSIGN_USER_TAG); + + const handleUnassignTag = async (): Promise => { + try { + await unassignUserTag({ + variables: { + tagId: currentTagId, + userId: unassignUserId, + }, + }); + + userTagAssignedMembersRefetch(); + toggleUnassignTagModal(); + toast.success(t('successfullyUnassigned') as string); + } catch (error: unknown) { + /* istanbul ignore next */ + if (error instanceof Error) { + toast.error(error.message); + } + } + }; + + const [edit] = useMutation(UPDATE_USER_TAG); + + const [newTagName, setNewTagName] = useState(''); + const currentTagName = userTagAssignedMembersData?.getUserTag.name ?? ''; + + useEffect(() => { + setNewTagName(userTagAssignedMembersData?.getUserTag.name ?? ''); + }, [userTagAssignedMembersData]); + + const editTag = async (e: FormEvent): Promise => { + e.preventDefault(); + + if (newTagName === currentTagName) { + toast.info(t('changeNameToEdit')); + return; + } + + try { + const { data } = await edit({ + variables: { + tagId: currentTagId, + name: newTagName, + }, + }); + + if (data) { + toast.success(t('tagUpdationSuccess')); + userTagAssignedMembersRefetch(); + orgUserTagsAncestorsRefetch(); + setEditTagModalIsOpen(false); + } + } catch (error: unknown) { + /* istanbul ignore next */ + if (error instanceof Error) { + toast.error(error.message); + } + } + }; + + const [removeUserTag] = useMutation(REMOVE_USER_TAG); + const handleRemoveUserTag = async (): Promise => { + try { + await removeUserTag({ + variables: { + id: currentTagId, + }, + }); + + navigate(`/orgtags/${orgId}`); + toggleRemoveUserTagModal(); + toast.success(t('tagRemovalSuccess') as string); + } catch (error: unknown) { + /* istanbul ignore next */ + if (error instanceof Error) { + toast.error(error.message); + } + } + }; + + if (userTagAssignedMembersLoading || orgUserTagsAncestorsLoading) { + return ; + } + + if (userTagAssignedMembersError || orgUserTagsAncestorsError) { + return ( +
    +
    + +
    + Error occured while loading{' '} + {userTagAssignedMembersError ? 'assigned users' : 'tag ancestors'} +
    + {userTagAssignedMembersError + ? userTagAssignedMembersError.message + : orgUserTagsAncestorsError?.message} +
    +
    +
    + ); + } + + const userTagAssignedMembers = + userTagAssignedMembersData?.getUserTag.usersAssignedTo.edges.map( + (edge) => edge.node, + ); + + const orgUserTagAncestors = orgUserTagAncestorsData?.getUserTagAncestors; + + const redirectToSubTags = (tagId: string): void => { + navigate(`/orgtags/${orgId}/subTags/${tagId}`); + }; + + const redirectToManageTag = (tagId: string): void => { + navigate(`/orgtags/${orgId}/managetag/${tagId}`); + }; + + const handleNextPage = (): void => { + setAfter( + userTagAssignedMembersData?.getUserTag.usersAssignedTo.pageInfo.endCursor, + ); + setBefore(null); + setFirst(5); + setLast(null); + }; + const handlePreviousPage = (): void => { + setBefore( + userTagAssignedMembersData?.getUserTag.usersAssignedTo.pageInfo + .startCursor, + ); + setAfter(null); + setFirst(null); + setLast(5); + }; + + const toggleUnassignTagModal = (): void => { + if (unassignTagModalIsOpen) { + setUnassignUserId(null); + } + setUnassignTagModalIsOpen(!unassignTagModalIsOpen); + }; + + const columns: GridColDef[] = [ + { + field: 'id', + headerName: '#', + minWidth: 100, + align: 'center', + headerAlign: 'center', + headerClassName: `${styles.tableHeader}`, + sortable: false, + renderCell: (params: GridCellParams) => { + return
    {params.row.id}
    ; + }, + }, + { + field: 'userName', + headerName: 'User Name', + flex: 2, + minWidth: 100, + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + return ( +
    + {params.row.firstName + ' ' + params.row.lastName} +
    + ); + }, + }, + { + field: 'actions', + headerName: 'Actions', + flex: 1, + align: 'center', + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + return ( +
    + +
    {t('viewProfile')}
    + + + +
    + ); + }, + }, + ]; + + return ( + <> + +
    +
    +
    + + +
    + +
    + + + + + +
    +
    + + + +
    +
    + +
    + +
    navigate(`/orgtags/${orgId}`)} + className={`fs-6 ms-3 my-1 ${styles.tagsBreadCrumbs}`} + data-testid="allTagsBtn" + > + {'Tags'} + +
    + + {orgUserTagAncestors?.map((tag, index) => ( +
    redirectToManageTag(tag._id as string)} + data-testid="redirectToManageTag" + > + {tag.name} + + {orgUserTagAncestors.length - 1 !== index && ( + /* istanbul ignore next */ + + )} +
    + ))} +
    + row._id} + slots={{ + noRowsOverlay: /* istanbul ignore next */ () => ( + + {t('noAssignedMembersFound')} + + ), + }} + sx={dataGridStyle} + getRowClassName={() => `${styles.rowBackground}`} + autoHeight + rowHeight={65} + rows={userTagAssignedMembers?.map((assignedMembers, index) => ({ + id: index + 1, + ...assignedMembers, + }))} + columns={columns} + isRowSelectable={() => false} + /> + +
    +
    + +
    +
    + +
    +
    + + + +
    +
    {'Actions'}
    +
    +
    +
    { + setTagActionType('assignToTags'); + showAssignToTagsModal(); + }} + className="ms-5 mt-2 mb-2 btn btn-primary btn-sm w-75" + data-testid="assignToTags" + > + {t('assignToTags')} +
    +
    { + setTagActionType('removeFromTags'); + showAssignToTagsModal(); + }} + className="ms-5 mb-3 btn btn-danger btn-sm w-75" + data-testid="removeFromTags" + > + {t('removeFromTags')} +
    + +
    + +
    + {tCommon('edit')} +
    +
    + {tCommon('remove')} +
    +
    + +
    +
    +
    + + {/* Add People To Tag Modal */} + + + {/* Assign People To Tags Modal */} + + + {/* Unassign Tag Modal */} + + + + {t('unassignUserTag')} + + + {t('unassignUserTagMessage')} + + + + + + + {/* Edit Tag Modal */} + + + {t('tagDetails')} + +
    + + {t('tagName')} + { + setNewTagName(e.target.value); + }} + /> + + + + + + +
    +
    + + {/* Remove User Tag Modal */} + + + + {t('removeUserTag')} + + + {t('removeUserTagMessage')} + + + + + + + ); +} + +export default ManageTag; diff --git a/src/screens/ManageTag/ManageTagMocks.ts b/src/screens/ManageTag/ManageTagMocks.ts new file mode 100644 index 0000000000..e90e8c58ed --- /dev/null +++ b/src/screens/ManageTag/ManageTagMocks.ts @@ -0,0 +1,569 @@ +import { + REMOVE_USER_TAG, + UNASSIGN_USER_TAG, + UPDATE_USER_TAG, +} from 'GraphQl/Mutations/TagMutations'; +import { ORGANIZATION_USER_TAGS_LIST } from 'GraphQl/Queries/OrganizationQueries'; +import { + USER_TAG_ANCESTORS, + USER_TAGS_ASSIGNED_MEMBERS, + USER_TAGS_MEMBERS_TO_ASSIGN_TO, +} from 'GraphQl/Queries/userTagQueries'; +import { TAGS_QUERY_LIMIT } from 'utils/organizationTagsUtils'; + +export const MOCKS = [ + { + request: { + query: USER_TAGS_ASSIGNED_MEMBERS, + variables: { + id: '1', + after: null, + before: null, + first: 5, + last: null, + }, + }, + result: { + data: { + getUserTag: { + name: 'tag1', + usersAssignedTo: { + edges: [ + { + node: { + _id: '1', + firstName: 'member', + lastName: '1', + }, + cursor: '1', + }, + { + node: { + _id: '2', + firstName: 'member', + lastName: '2', + }, + cursor: '2', + }, + { + node: { + _id: '3', + firstName: 'member', + lastName: '3', + }, + cursor: '3', + }, + { + node: { + _id: '4', + firstName: 'member', + lastName: '4', + }, + cursor: '4', + }, + { + node: { + _id: '5', + firstName: 'member', + lastName: '5', + }, + cursor: '5', + }, + ], + pageInfo: { + startCursor: '1', + endCursor: '5', + hasNextPage: true, + hasPreviousPage: false, + }, + totalCount: 6, + }, + }, + }, + }, + }, + { + request: { + query: USER_TAGS_ASSIGNED_MEMBERS, + variables: { + id: '1', + after: '5', + before: null, + first: 5, + last: null, + }, + }, + result: { + data: { + getUserTag: { + name: 'tag1', + usersAssignedTo: { + edges: [ + { + node: { + _id: '6', + firstName: 'member', + lastName: '6', + }, + cursor: '6', + }, + ], + pageInfo: { + startCursor: '6', + endCursor: '6', + hasNextPage: false, + hasPreviousPage: true, + }, + totalCount: 6, + }, + }, + }, + }, + }, + { + request: { + query: USER_TAGS_ASSIGNED_MEMBERS, + variables: { + id: '1', + after: null, + before: '6', + first: null, + last: 5, + }, + }, + result: { + data: { + getUserTag: { + name: 'tag1', + usersAssignedTo: { + edges: [ + { + node: { + _id: '1', + firstName: 'member', + lastName: '1', + }, + cursor: '1', + }, + { + node: { + _id: '2', + firstName: 'member', + lastName: '2', + }, + cursor: '2', + }, + { + node: { + _id: '3', + firstName: 'member', + lastName: '3', + }, + cursor: '3', + }, + { + node: { + _id: '4', + firstName: 'member', + lastName: '4', + }, + cursor: '4', + }, + { + node: { + _id: '5', + firstName: 'member', + lastName: '5', + }, + cursor: '5', + }, + ], + pageInfo: { + startCursor: '1', + endCursor: '5', + hasNextPage: true, + hasPreviousPage: false, + }, + totalCount: 6, + }, + }, + }, + }, + }, + { + request: { + query: USER_TAGS_MEMBERS_TO_ASSIGN_TO, + variables: { + id: '1', + first: 7, + }, + }, + result: { + data: { + getUserTag: { + name: 'tag1', + usersToAssignTo: { + edges: [ + { + node: { + _id: '1', + firstName: 'member', + lastName: '1', + }, + cursor: '1', + }, + { + node: { + _id: '2', + firstName: 'member', + lastName: '2', + }, + cursor: '2', + }, + { + node: { + _id: '3', + firstName: 'member', + lastName: '3', + }, + cursor: '3', + }, + { + node: { + _id: '4', + firstName: 'member', + lastName: '4', + }, + cursor: '4', + }, + { + node: { + _id: '5', + firstName: 'member', + lastName: '5', + }, + cursor: '5', + }, + { + node: { + _id: '6', + firstName: 'member', + lastName: '6', + }, + cursor: '6', + }, + { + node: { + _id: '7', + firstName: 'member', + lastName: '7', + }, + cursor: '7', + }, + ], + pageInfo: { + startCursor: '1', + endCursor: '7', + hasNextPage: true, + hasPreviousPage: false, + }, + totalCount: 10, + }, + }, + }, + }, + }, + { + request: { + query: USER_TAG_ANCESTORS, + variables: { + id: '1', + }, + }, + result: { + data: { + getUserTagAncestors: [ + { + _id: '1', + name: 'tag1', + }, + ], + }, + }, + }, + { + request: { + query: UNASSIGN_USER_TAG, + variables: { + tagId: '1', + userId: '1', + }, + }, + result: { + data: { + unassignUserTag: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: ORGANIZATION_USER_TAGS_LIST, + variables: { + id: '123', + first: TAGS_QUERY_LIMIT, + }, + }, + result: { + data: { + organizations: [ + { + userTags: { + edges: [ + { + node: { + _id: '1', + name: 'userTag 1', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 11, + }, + }, + cursor: '1', + }, + { + node: { + _id: '2', + name: 'userTag 2', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 0, + }, + }, + cursor: '2', + }, + { + node: { + _id: '3', + name: 'userTag 3', + usersAssignedTo: { + totalCount: 0, + }, + childTags: { + totalCount: 5, + }, + }, + cursor: '3', + }, + { + node: { + _id: '4', + name: 'userTag 4', + usersAssignedTo: { + totalCount: 0, + }, + childTags: { + totalCount: 0, + }, + }, + cursor: '4', + }, + { + node: { + _id: '5', + name: 'userTag 5', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 5, + }, + }, + cursor: '5', + }, + { + node: { + _id: '6', + name: 'userTag 6', + usersAssignedTo: { + totalCount: 6, + }, + childTags: { + totalCount: 6, + }, + }, + cursor: '6', + }, + { + node: { + _id: '7', + name: 'userTag 7', + usersAssignedTo: { + totalCount: 7, + }, + childTags: { + totalCount: 7, + }, + }, + cursor: '7', + }, + { + node: { + _id: '8', + name: 'userTag 8', + usersAssignedTo: { + totalCount: 8, + }, + childTags: { + totalCount: 8, + }, + }, + cursor: '8', + }, + { + node: { + _id: '9', + name: 'userTag 9', + usersAssignedTo: { + totalCount: 9, + }, + childTags: { + totalCount: 9, + }, + }, + cursor: '9', + }, + { + node: { + _id: '10', + name: 'userTag 10', + usersAssignedTo: { + totalCount: 10, + }, + childTags: { + totalCount: 10, + }, + }, + cursor: '10', + }, + ], + pageInfo: { + startCursor: '1', + endCursor: '10', + hasNextPage: true, + hasPreviousPage: false, + }, + totalCount: 12, + }, + }, + ], + }, + }, + }, + { + request: { + query: UPDATE_USER_TAG, + variables: { + tagId: '1', + name: 'tag 1 edited', + }, + }, + result: { + data: { + updateUserTag: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: REMOVE_USER_TAG, + variables: { + id: '1', + }, + }, + result: { + data: { + removeUserTag: { + _id: '1', + }, + }, + }, + }, +]; + +export const MOCKS_ERROR_ASSIGNED_MEMBERS = [ + { + request: { + query: USER_TAGS_ASSIGNED_MEMBERS, + variables: { + id: '1', + after: null, + before: null, + first: 5, + last: null, + }, + }, + error: new Error('Mock Graphql Error'), + }, + { + request: { + query: USER_TAG_ANCESTORS, + variables: { + id: '1', + }, + }, + result: { + data: { + getUserTagAncestors: [], + }, + }, + }, +]; + +export const MOCKS_ERROR_TAG_ANCESTORS = [ + { + request: { + query: USER_TAGS_ASSIGNED_MEMBERS, + variables: { + id: '1', + after: null, + before: null, + first: 5, + last: null, + }, + }, + result: { + data: { + getUserTag: { + name: 'tag1', + usersAssignedTo: { + edges: [], + pageInfo: { + startCursor: '1', + endCursor: '5', + hasNextPage: true, + hasPreviousPage: false, + }, + totalCount: 6, + }, + }, + }, + }, + }, + { + request: { + query: USER_TAG_ANCESTORS, + variables: { + id: '1', + }, + }, + error: new Error('Mock Graphql Error'), + }, +]; diff --git a/src/screens/MemberDetail/MemberDetail.test.tsx b/src/screens/MemberDetail/MemberDetail.test.tsx index 02e9fe8719..eaea79d8c5 100644 --- a/src/screens/MemberDetail/MemberDetail.test.tsx +++ b/src/screens/MemberDetail/MemberDetail.test.tsx @@ -445,31 +445,6 @@ describe('MemberDetail', () => { // expect(screen.getByText(/Display Image/i)).toBeInTheDocument(); }); - // test('should display warnings for blank form submission', async () => { - // jest.spyOn(toast, 'warning'); - // const props = { - // key: '123', - // id: '1', - // toggleStateValue: jest.fn(), - // }; - - // render( - // - // - // - // - // - // - // - // - // , - // ); - - // await wait(); - // expect(toast.warning).toHaveBeenCalledWith('First Name cannot be blank!'); - // expect(toast.warning).toHaveBeenCalledWith('Last Name cannot be blank!'); - // expect(toast.warning).toHaveBeenCalledWith('Email cannot be blank!'); - // }); test('display admin', async () => { const props = { id: 'rishav-jha-mech', diff --git a/src/screens/MemberDetail/MemberDetail.tsx b/src/screens/MemberDetail/MemberDetail.tsx index a2d68109e5..ddfc649f3b 100644 --- a/src/screens/MemberDetail/MemberDetail.tsx +++ b/src/screens/MemberDetail/MemberDetail.tsx @@ -33,6 +33,15 @@ type MemberDetailProps = { id?: string; }; +/** + * MemberDetail component is used to display the details of a user. + * It also allows the user to update the details. It uses the UPDATE_USER_MUTATION to update the user details. + * It uses the USER_DETAILS query to get the user details. It uses the useLocalStorage hook to store the user + * details in the local storage. + * @param id - The id of the user whose details are to be displayed. + * @returns React component + * + */ const MemberDetail: React.FC = ({ id }): JSX.Element => { const { t } = useTranslation('translation', { keyPrefix: 'memberDetail', @@ -173,7 +182,7 @@ const MemberDetail: React.FC = ({ id }): JSX.Element => { setItem('Email', email); setItem('UserImage', image); } - toast.success('Successful updated'); + toast.success(tCommon('successfullyUpdated') as string); } } catch (error: unknown) { if (error instanceof Error) { @@ -539,7 +548,6 @@ const MemberDetail: React.FC = ({ id }): JSX.Element => {
    } + /> +
    } + /> +
    } + /> + - + - , - ); - await wait(); - await waitFor(() => { - expect(getByText(translations.addCampaign)).toBeInTheDocument(); - }); + + , + ); +}; + +describe('FundCampaigns Screen', () => { + beforeEach(() => { + jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: 'orgId', fundId: 'fundId' }), + })); }); - it('renders the campaign screen with error', async () => { - const { queryByText } = render( - - - - - {} - - - - , - ); - await wait(); - await waitFor(() => { - expect(queryByText(translations.addCampaign)).not.toBeInTheDocument(); - }); + + afterEach(() => { + cleanup(); }); - it('renders the Error Component', async () => { - render( - - - - - {} - - - - , - ); - await wait(); + + afterAll(() => { + jest.clearAllMocks(); + }); + + it('should render the Campaign Pledge screen', async () => { + renderFundCampaign(link1); await waitFor(() => { - expect(screen.getByTestId('errorMsg')).toBeInTheDocument(); + expect(screen.getByTestId('searchFullName')).toBeInTheDocument(); }); + + expect(screen.getByText('Campaign 1')).toBeInTheDocument(); + expect(screen.getByText('Campaign 2')).toBeInTheDocument(); }); - it("opens and closes the 'Create Campaign' modal", async () => { + + it('should redirect to fallback URL if URL params are undefined', async () => { render( - - + + - {} + + } + /> +
    } + /> + - - + + , ); - await wait(); - await waitFor(() => - expect(screen.getByTestId('addCampaignBtn')).toBeInTheDocument(), - ); - userEvent.click(screen.getByTestId('addCampaignBtn')); await waitFor(() => { - return expect( - screen.findByTestId('createCampaignCloseBtn'), - ).resolves.toBeInTheDocument(); + expect(screen.getByTestId('paramsError')).toBeInTheDocument(); }); - userEvent.click(screen.getByTestId('createCampaignCloseBtn')); - await waitForElementToBeRemoved(() => - screen.queryByTestId('createCampaignCloseBtn'), - ); }); - it('creates a new Campaign', async () => { - render( - - - - - - {} - - - - - , - ); - await wait(); + + it('open and close Create Campaign modal', async () => { + renderFundCampaign(link1); + + const addCampaignBtn = await screen.findByTestId('addCampaignBtn'); + expect(addCampaignBtn).toBeInTheDocument(); + userEvent.click(addCampaignBtn); + await waitFor(() => - expect(screen.getByTestId('addCampaignBtn')).toBeInTheDocument(), - ); - userEvent.click(screen.getByTestId('addCampaignBtn')); - await waitFor(() => { - return expect( - screen.findByTestId('createCampaignCloseBtn'), - ).resolves.toBeInTheDocument(); - }); - userEvent.type( - screen.getByPlaceholderText('Enter Campaign Name'), - formData.campaignName, + expect(screen.getAllByText(translations.createCampaign)).toHaveLength(2), ); - userEvent.type( - screen.getByPlaceholderText('Enter Funding Goal'), - formData.campaignGoal.toString(), + userEvent.click(screen.getByTestId('campaignCloseBtn')); + await waitFor(() => + expect(screen.queryByTestId('campaignCloseBtn')).toBeNull(), ); - const currency = screen.getByTestId('currencySelect'); - fireEvent.change(currency, { - target: { value: formData.campaignCurrency }, - }); - const startDate = screen.getByLabelText('Start Date'); - const endDate = screen.getByLabelText('End Date'); - fireEvent.change(startDate, { - target: { value: formData.campaignStartDate }, - }); - fireEvent.change(endDate, { - target: { value: formData.campaignEndDate }, - }); + }); - userEvent.click(screen.getByTestId('createCampaignBtn')); + it('open and close update campaign modal', async () => { + renderFundCampaign(link1); await waitFor(() => { - expect(toast.success).toHaveBeenCalledWith(translations.createdCampaign); + expect(screen.getByTestId('searchFullName')).toBeInTheDocument(); }); - }); - it('toast an error on unsuccessful campaign creation', async () => { - render( - - - - - - {} - - - - - , - ); - await wait(); + + const editCampaignBtn = await screen.findAllByTestId('editCampaignBtn'); + await waitFor(() => expect(editCampaignBtn[0]).toBeInTheDocument()); + userEvent.click(editCampaignBtn[0]); + await waitFor(() => - expect(screen.getByTestId('addCampaignBtn')).toBeInTheDocument(), + expect( + screen.getAllByText(translations.updateCampaign)[0], + ).toBeInTheDocument(), ); - userEvent.click(screen.getByTestId('addCampaignBtn')); - await waitFor(() => { - return expect( - screen.findByTestId('createCampaignCloseBtn'), - ).resolves.toBeInTheDocument(); - }); - userEvent.type( - screen.getByPlaceholderText('Enter Campaign Name'), - formData.campaignName, - ); - userEvent.type( - screen.getByPlaceholderText('Enter Funding Goal'), - formData.campaignGoal.toString(), + userEvent.click(screen.getByTestId('campaignCloseBtn')); + await waitFor(() => + expect(screen.queryByTestId('campaignCloseBtn')).toBeNull(), ); - const endDateDatePicker = screen.getByLabelText('End Date'); - const startDateDatePicker = screen.getByLabelText('Start Date'); + }); - fireEvent.change(endDateDatePicker, { - target: { value: formData.campaignEndDate }, - }); - fireEvent.change(startDateDatePicker, { - target: { value: formData.campaignStartDate }, + it('Search the Campaigns list by Name', async () => { + renderFundCampaign(link1); + const searchField = await screen.findByTestId('searchFullName'); + fireEvent.change(searchField, { + target: { value: '2' }, }); - userEvent.click(screen.getByTestId('createCampaignBtn')); - await waitFor(() => { - expect(toast.error).toHaveBeenCalled(); + expect(screen.getByText('Campaign 2')).toBeInTheDocument(); + expect(screen.queryByText('Campaign 1')).toBeNull(); }); }); - it('opens and closes the Edit Campaign modal', async () => { - render( - - - - - - {} - - - - - , - ); - await wait(); - await waitFor(() => - expect(screen.getAllByTestId('editCampaignBtn')[0]).toBeInTheDocument(), - ); - userEvent.click(screen.getAllByTestId('editCampaignBtn')[0]); + + it('should render the Campaign screen with error', async () => { + renderFundCampaign(link2); await waitFor(() => { - return expect( - screen.findByTestId('editCampaignCloseBtn'), - ).resolves.toBeInTheDocument(); + expect(screen.getByTestId('errorMsg')).toBeInTheDocument(); }); - userEvent.click(screen.getByTestId('editCampaignCloseBtn')); - await waitForElementToBeRemoved(() => - screen.queryByTestId('editCampaignCloseBtn'), - ); }); - it("updates the Campaign's details", async () => { - render( - - - - - - {} - - - - - , - ); - await wait(); + it('renders the empty campaign component', async () => { + renderFundCampaign(link3); await waitFor(() => - expect(screen.getAllByTestId('editCampaignBtn')[0]).toBeInTheDocument(), + expect( + screen.getByText(translations.noCampaignsFound), + ).toBeInTheDocument(), ); - userEvent.click(screen.getAllByTestId('editCampaignBtn')[0]); - await waitFor(() => { - return expect( - screen.findByTestId('editCampaignCloseBtn'), - ).resolves.toBeInTheDocument(); - }); - const campaignName = screen.getByPlaceholderText('Enter Campaign Name'); - fireEvent.change(campaignName, { - target: { value: 'Campaign 4' }, - }); - const fundingGoal = screen.getByPlaceholderText('Enter Funding Goal'); - fireEvent.change(fundingGoal, { - target: { value: 1000 }, - }); - const currency = screen.getByTestId('currencySelect'); - fireEvent.change(currency, { - target: { value: 'INR' }, - }); - const endDateDatePicker = screen.getByLabelText('End Date'); - const startDateDatePicker = screen.getByLabelText('Start Date'); - - const endDate = - formData.campaignEndDate < formData.campaignStartDate - ? formData.campaignStartDate - : formData.campaignEndDate; - fireEvent.change(endDateDatePicker, { - target: { value: endDate }, - }); + }); - fireEvent.change(startDateDatePicker, { - target: { value: formData.campaignStartDate }, - }); + it('Sort the Campaigns list by Latest end Date', async () => { + renderFundCampaign(link1); - userEvent.click(screen.getByTestId('editCampaignSubmitBtn')); + const sortBtn = await screen.findByTestId('filter'); + expect(sortBtn).toBeInTheDocument(); - await waitFor(() => { - expect(toast.success).toHaveBeenCalledWith(translations.updatedCampaign); - }); - }); + fireEvent.click(sortBtn); + fireEvent.click(screen.getByTestId('endDate_DESC')); - it("updates the Campaign's details when date is null", async () => { - render( - - - - - - {} - - - - - , - ); - await wait(); - await waitFor(() => - expect(screen.getAllByTestId('editCampaignBtn')[0]).toBeInTheDocument(), - ); - userEvent.click(screen.getAllByTestId('editCampaignBtn')[0]); await waitFor(() => { - return expect( - screen.findByTestId('editCampaignCloseBtn'), - ).resolves.toBeInTheDocument(); + expect(screen.getByText('Campaign 1')).toBeInTheDocument(); + expect(screen.queryByText('Campaign 2')).toBeInTheDocument(); }); - const endDateDatePicker = screen.getByLabelText('End Date'); - const startDateDatePicker = screen.getByLabelText('Start Date'); - fireEvent.change(endDateDatePicker, { - target: { value: null }, - }); - - fireEvent.change(startDateDatePicker, { - target: { value: null }, + await waitFor(() => { + expect(screen.getAllByTestId('endDateCell')[0]).toHaveTextContent( + '01/01/2024', + ); }); - - expect(startDateDatePicker.getAttribute('value')).toBe(''); - expect(endDateDatePicker.getAttribute('value')).toBe(''); }); - it("updates the Campaign's details when endDate is less than date", async () => { - const formData = { - campaignName: 'Campaign 1', - campaignCurrency: 'USD', - campaignGoal: 100, - campaignStartDate: '03/10/2024', - campaignEndDate: '03/10/2023', - }; - render( - - - - - - {} - - - - - , - ); - await wait(); - await waitFor(() => - expect(screen.getAllByTestId('editCampaignBtn')[0]).toBeInTheDocument(), - ); - userEvent.click(screen.getAllByTestId('editCampaignBtn')[0]); - await waitFor(() => { - return expect( - screen.findByTestId('editCampaignCloseBtn'), - ).resolves.toBeInTheDocument(); - }); + it('Sort the Campaigns list by Earliest end Date', async () => { + renderFundCampaign(link1); - const endDateDatePicker = screen.getByLabelText('End Date'); - const startDateDatePicker = screen.getByLabelText('Start Date'); + const sortBtn = await screen.findByTestId('filter'); + expect(sortBtn).toBeInTheDocument(); - fireEvent.change(endDateDatePicker, { - target: { value: formData.campaignEndDate }, - }); + fireEvent.click(sortBtn); + fireEvent.click(screen.getByTestId('endDate_ASC')); - fireEvent.change(startDateDatePicker, { - target: { value: formData.campaignStartDate }, + await waitFor(() => { + expect(screen.getByText('Campaign 1')).toBeInTheDocument(); + expect(screen.queryByText('Campaign 2')).toBeInTheDocument(); }); - }); - it("doesn't update when fund field has value less than or equal to 0", async () => { - render( - - - - - - {} - - - - - , - ); - await wait(); - await waitFor(() => - expect(screen.getAllByTestId('editCampaignBtn')[0]).toBeInTheDocument(), - ); - userEvent.click(screen.getAllByTestId('editCampaignBtn')[0]); await waitFor(() => { - return expect( - screen.findByTestId('editCampaignCloseBtn'), - ).resolves.toBeInTheDocument(); + expect(screen.getAllByTestId('endDateCell')[0]).toHaveTextContent( + '01/01/2021', + ); }); - const fundingGoal = screen.getByPlaceholderText( - 'Enter Funding Goal', - ) as HTMLInputElement; + }); - const initialValue = fundingGoal.value; //Vakue before updating + it('Sort the Campaigns list by lowest goal', async () => { + renderFundCampaign(link1); - fireEvent.change(fundingGoal, { - target: { value: 0 }, - }); + const sortBtn = await screen.findByTestId('filter'); + expect(sortBtn).toBeInTheDocument(); - expect(fundingGoal.value).toBe(initialValue); //Retains previous value - }); + fireEvent.click(sortBtn); + fireEvent.click(screen.getByTestId('fundingGoal_ASC')); - it('toast an error on unsuccessful campaign update', async () => { - render( - - - - - - {} - - - - - , - ); - await wait(); - await waitFor(() => - expect(screen.getAllByTestId('editCampaignBtn')[0]).toBeInTheDocument(), - ); - userEvent.click(screen.getAllByTestId('editCampaignBtn')[0]); await waitFor(() => { - return expect( - screen.findByTestId('editCampaignCloseBtn'), - ).resolves.toBeInTheDocument(); + expect(screen.getByText('Campaign 1')).toBeInTheDocument(); + expect(screen.queryByText('Campaign 2')).toBeInTheDocument(); }); - userEvent.type( - screen.getByPlaceholderText('Enter Campaign Name'), - formData.campaignName, - ); - - userEvent.click(screen.getByTestId('editCampaignSubmitBtn')); await waitFor(() => { - expect(toast.error).toHaveBeenCalled(); - }); - }); - it("opens and closes the 'Delete Campaign' modal", async () => { - render( - - - - - - {} - - - - - , - ); - await wait(); - await waitFor(() => - expect(screen.getAllByTestId('editCampaignBtn')[0]).toBeInTheDocument(), - ); - userEvent.click(screen.getAllByTestId('editCampaignBtn')[0]); - await wait(); - await waitFor(() => - expect(screen.getAllByTestId('deleteCampaignBtn')[0]).toBeInTheDocument(), - ); - userEvent.click(screen.getAllByTestId('deleteCampaignBtn')[0]); - await waitFor(() => { - return expect( - screen.findByTestId('deleteCampaignCloseBtn'), - ).resolves.toBeInTheDocument(); + expect(screen.getAllByTestId('goalCell')[0]).toHaveTextContent('100'); }); - userEvent.click(screen.getByTestId('deleteCampaignCloseBtn')); - await waitForElementToBeRemoved(() => - screen.queryByTestId('deleteCampaignCloseBtn'), - ); }); - it('deletes a Campaign', async () => { - render( - - - - - - {} - - - - - , - ); - await wait(); - await waitFor(() => - expect(screen.getAllByTestId('editCampaignBtn')[0]).toBeInTheDocument(), - ); - userEvent.click(screen.getAllByTestId('editCampaignBtn')[0]); - await wait(); - await waitFor(() => - expect(screen.getAllByTestId('deleteCampaignBtn')[0]).toBeInTheDocument(), - ); - userEvent.click(screen.getAllByTestId('deleteCampaignBtn')[0]); + + it('Sort the Campaigns list by highest goal', async () => { + renderFundCampaign(link1); + + const sortBtn = await screen.findByTestId('filter'); + expect(sortBtn).toBeInTheDocument(); + + fireEvent.click(sortBtn); + fireEvent.click(screen.getByTestId('fundingGoal_DESC')); + await waitFor(() => { - return expect( - screen.findByTestId('deleteCampaignCloseBtn'), - ).resolves.toBeInTheDocument(); + expect(screen.getByText('Campaign 1')).toBeInTheDocument(); + expect(screen.queryByText('Campaign 2')).toBeInTheDocument(); }); - userEvent.click(screen.getByTestId('deleteyesbtn')); + await waitFor(() => { - expect(toast.success).toHaveBeenCalledWith(translations.deletedCampaign); + expect(screen.getAllByTestId('goalCell')[0]).toHaveTextContent('200'); }); }); - it('toast an error on unsuccessful campaign deletion', async () => { - render( - - - - - - {} - - - - - , - ); - await wait(); - await waitFor(() => - expect(screen.getAllByTestId('editCampaignBtn')[0]).toBeInTheDocument(), - ); - userEvent.click(screen.getAllByTestId('editCampaignBtn')[0]); - await wait(); - await waitFor(() => - expect(screen.getAllByTestId('deleteCampaignBtn')[0]).toBeInTheDocument(), - ); - userEvent.click(screen.getAllByTestId('deleteCampaignBtn')[0]); - await waitFor(() => { - return expect( - screen.findByTestId('deleteCampaignCloseBtn'), - ).resolves.toBeInTheDocument(); - }); - userEvent.click(screen.getByTestId('deleteyesbtn')); + + it('Click on Campaign Name', async () => { + renderFundCampaign(link1); + + const campaignName = await screen.findAllByTestId('campaignName'); + expect(campaignName[0]).toBeInTheDocument(); + fireEvent.click(campaignName[0]); + await waitFor(() => { - expect(toast.error).toHaveBeenCalled(); + expect(screen.getByTestId('pledgeScreen')).toBeInTheDocument(); }); }); - it('renders the Empty Campaigns Component', async () => { - render( - - - - - - {} - - - - - , - ); - await wait(); + + it('Click on View Pledge', async () => { + renderFundCampaign(link1); + + const viewBtn = await screen.findAllByTestId('viewBtn'); + expect(viewBtn[0]).toBeInTheDocument(); + fireEvent.click(viewBtn[0]); + await waitFor(() => { - expect(screen.getByText(translations.noCampaigns)).toBeInTheDocument(); + expect(screen.getByTestId('pledgeScreen')).toBeInTheDocument(); }); }); - it("redirects to 'FundCampaignPledge' screen", async () => { - render( - - - - - - {} - - - - - , - ); - await wait(); - await waitFor(() => - expect(screen.getAllByTestId('campaignName')[0]).toBeInTheDocument(), - ); - userEvent.click(screen.getAllByTestId('campaignName')[0]); + + it('should render the Fund screen on fund breadcrumb click', async () => { + renderFundCampaign(link1); + + const fundBreadcrumb = await screen.findByTestId('fundsLink'); + expect(fundBreadcrumb).toBeInTheDocument(); + fireEvent.click(fundBreadcrumb); + await waitFor(() => { - expect(mockNavigate).toHaveBeenCalledWith( - '/fundCampaignPledge/undefined/1', - ); + expect(screen.getByTestId('fundScreen')).toBeInTheDocument(); }); }); - - it('search funds by name', async () => { - render( - - - - - {} - - - - , - ); - await wait(); - userEvent.type(screen.getByTestId('searchFullName'), 'Funndds'); - await wait(); - userEvent.click(screen.getByTestId('searchBtn')); - }); }); diff --git a/src/screens/OrganizationFundCampaign/OrganizationFundCampaignMocks.tsx b/src/screens/OrganizationFundCampaign/OrganizationFundCampaignMocks.ts similarity index 57% rename from src/screens/OrganizationFundCampaign/OrganizationFundCampaignMocks.tsx rename to src/screens/OrganizationFundCampaign/OrganizationFundCampaignMocks.ts index 09fbb9f4b2..fa871c3593 100644 --- a/src/screens/OrganizationFundCampaign/OrganizationFundCampaignMocks.tsx +++ b/src/screens/OrganizationFundCampaign/OrganizationFundCampaignMocks.ts @@ -1,6 +1,5 @@ import { CREATE_CAMPAIGN_MUTATION, - DELETE_CAMPAIGN_MUTATION, UPDATE_CAMPAIGN_MUTATION, } from 'GraphQl/Mutations/CampaignMutation'; import { FUND_CAMPAIGN } from 'GraphQl/Queries/fundQueries'; @@ -10,15 +9,19 @@ export const MOCKS = [ request: { query: FUND_CAMPAIGN, variables: { - id: undefined, + id: 'fundId', + orderBy: null, + where: { name_contains: '' }, }, }, result: { data: { getFundById: { + name: 'Fund 1', + isArchived: false, campaigns: [ { - _id: '1', + _id: 'campaignId1', name: 'Campaign 1', fundingGoal: 100, startDate: '2024-01-01', @@ -40,92 +43,119 @@ export const MOCKS = [ }, { request: { - query: CREATE_CAMPAIGN_MUTATION, + query: FUND_CAMPAIGN, variables: { - fundId: undefined, - name: 'Campaign 1', - fundingGoal: 100, - startDate: '2024-03-10', - endDate: '2024-03-10', - currency: 'USD', + id: 'fundId', + orderBy: null, + where: { name_contains: '2' }, }, }, result: { data: { - createFundraisingCampaign: { - _id: '3', + getFundById: { + name: 'Fund 1', + isArchived: false, + campaigns: [ + { + _id: '2', + name: 'Campaign 2', + fundingGoal: 200, + startDate: '2021-01-01', + endDate: '2021-01-01', + currency: 'USD', + }, + ], }, }, }, }, { request: { - query: UPDATE_CAMPAIGN_MUTATION, + query: FUND_CAMPAIGN, variables: { - id: '1', - name: 'Campaign 4', - startDate: '2024-03-10', - endDate: '2024-03-10', - fundingGoal: 1000, - currency: 'INR', + id: 'fundId', + orderBy: 'endDate_DESC', + where: { name_contains: '' }, }, }, result: { data: { - updateFundraisingCampaign: { - _id: '1', + getFundById: { + name: 'Fund 1', + isArchived: false, + campaigns: [ + { + _id: '1', + name: 'Campaign 1', + fundingGoal: 100, + startDate: '2024-01-01', + endDate: '2024-01-01', + currency: 'USD', + }, + { + _id: '2', + name: 'Campaign 2', + fundingGoal: 200, + startDate: '2021-01-01', + endDate: '2021-01-01', + currency: 'USD', + }, + ], }, }, }, }, { request: { - query: DELETE_CAMPAIGN_MUTATION, + query: FUND_CAMPAIGN, variables: { - id: '1', + id: 'fundId', + orderBy: 'endDate_ASC', + where: { name_contains: '' }, }, }, result: { data: { - removeFundraisingCampaign: { - _id: '1', + getFundById: { + name: 'Fund 1', + isArchived: false, + campaigns: [ + { + _id: '2', + name: 'Campaign 2', + fundingGoal: 200, + startDate: '2021-01-01', + endDate: '2021-01-01', + currency: 'USD', + }, + { + _id: '1', + name: 'Campaign 1', + fundingGoal: 100, + startDate: '2024-01-01', + endDate: '2024-01-01', + currency: 'USD', + }, + ], }, }, }, }, -]; - -export const MOCK_FUND_CAMPAIGN_ERROR = [ { request: { query: FUND_CAMPAIGN, variables: { - id: undefined, - }, - }, - error: new Error('An error occurred'), - }, -]; -export const MOCKS_ERROR_CREATE_CAMPAIGN = [ - { - request: { - query: FUND_CAMPAIGN, - variables: { - id: undefined, + id: 'fundId', + orderBy: 'fundingGoal_DESC', + where: { name_contains: '' }, }, }, result: { data: { getFundById: { + name: 'Fund 1', + isArchived: false, campaigns: [ - { - _id: '1', - name: 'Campaign 1', - fundingGoal: 100, - startDate: '2021-01-01', - endDate: '2021-01-01', - currency: 'USD', - }, { _id: '2', name: 'Campaign 2', @@ -134,45 +164,40 @@ export const MOCKS_ERROR_CREATE_CAMPAIGN = [ endDate: '2021-01-01', currency: 'USD', }, + { + _id: '1', + name: 'Campaign 1', + fundingGoal: 100, + startDate: '2024-01-01', + endDate: '2024-01-01', + currency: 'USD', + }, ], }, }, }, }, - - { - request: { - query: CREATE_CAMPAIGN_MUTATION, - variables: { - fundId: undefined, - name: 'Campaign 1', - fundingGoal: 100, - startDate: '2024-03-10', - endDate: '2024-03-10', - currency: 'USD', - }, - }, - error: new Error('An error occurred'), - }, -]; -export const MOCKS_ERROR_UPDATE_CAMPAIGN = [ { request: { query: FUND_CAMPAIGN, variables: { - id: undefined, + id: 'fundId', + orderBy: 'fundingGoal_ASC', + where: { name_contains: '' }, }, }, result: { data: { getFundById: { + name: 'Fund 1', + isArchived: false, campaigns: [ { _id: '1', name: 'Campaign 1', fundingGoal: 100, - startDate: '2021-01-01', - endDate: '2021-01-01', + startDate: '2024-01-01', + endDate: '2024-01-01', currency: 'USD', }, { @@ -190,73 +215,103 @@ export const MOCKS_ERROR_UPDATE_CAMPAIGN = [ }, { request: { - query: UPDATE_CAMPAIGN_MUTATION, + query: CREATE_CAMPAIGN_MUTATION, variables: { - id: undefined, - name: 'Campaign 1', - fundingGoal: 100, - startDate: '2024-03-10', - endDate: '2024-03-10', + fundId: 'fundId', + organizationId: 'orgId', + name: 'Campaign 2', + fundingGoal: 200, + startDate: '2024-01-02', + endDate: '2024-02-02', currency: 'USD', }, }, - error: new Error('An error occurred'), + result: { + data: { + createFundraisingCampaign: { + _id: 'fundId', + }, + }, + }, }, -]; -export const MOCKS_ERROR_DELETE_CAMPAIGN = [ { request: { - query: FUND_CAMPAIGN, + query: UPDATE_CAMPAIGN_MUTATION, variables: { - id: undefined, + id: 'campaignId1', + name: 'Campaign 4', + fundingGoal: 400, + startDate: '2023-01-02', + endDate: '2023-02-02', }, }, result: { data: { - getFundById: { - campaigns: [ - { - _id: '1', - name: 'Campaign 1', - fundingGoal: 100, - startDate: '2021-01-01', - endDate: '2021-01-01', - currency: 'USD', - }, - { - _id: '2', - name: 'Campaign 2', - fundingGoal: 200, - startDate: '2021-01-01', - endDate: '2021-01-01', - currency: 'USD', - }, - ], + updateFundraisingCampaign: { + _id: 'campaignId1', }, }, }, }, +]; + +export const MOCK_ERROR = [ { request: { - query: DELETE_CAMPAIGN_MUTATION, + query: FUND_CAMPAIGN, variables: { - id: '1', + id: 'fundId', + orderBy: null, + where: { name_contains: '2' }, }, }, error: new Error('An error occurred'), }, + { + request: { + query: CREATE_CAMPAIGN_MUTATION, + variables: { + fundId: 'fundId', + organizationId: 'orgId', + name: 'Campaign 2', + fundingGoal: 200, + startDate: '2024-01-02', + endDate: '2024-02-02', + currency: 'USD', + }, + }, + error: new Error('Mock graphql error'), + }, + { + request: { + query: UPDATE_CAMPAIGN_MUTATION, + variables: { + id: 'campaignId1', + name: 'Campaign 4', + fundingGoal: 400, + startDate: '2023-01-02', + endDate: '2023-02-02', + }, + }, + error: new Error('Mock graphql error'), + }, ]; + export const EMPTY_MOCKS = [ { request: { query: FUND_CAMPAIGN, variables: { - id: undefined, + id: 'fundId', + orderBy: null, + where: { name_contains: '' }, }, }, result: { data: { getFundById: { + name: 'Fund 1', + isArchived: false, campaigns: [], }, }, diff --git a/src/screens/OrganizationFunds/FundCreateModal.tsx b/src/screens/OrganizationFunds/FundCreateModal.tsx deleted file mode 100644 index 4dcf32c265..0000000000 --- a/src/screens/OrganizationFunds/FundCreateModal.tsx +++ /dev/null @@ -1,118 +0,0 @@ -import React from 'react'; -import type { ChangeEvent } from 'react'; -import { Button, Form, Modal } from 'react-bootstrap'; -import type { InterfaceCreateFund } from 'utils/interfaces'; -import styles from './OrganizationFunds.module.css'; - -interface InterfaceFundCreateModal { - fundCreateModalIsOpen: boolean; - hideCreateModal: () => void; - formState: InterfaceCreateFund; - setFormState: (state: React.SetStateAction) => void; - createFundHandler: (e: ChangeEvent) => Promise; - taxDeductible: boolean; - setTaxDeductible: (state: React.SetStateAction) => void; - isDefault: boolean; - setIsDefault: (state: React.SetStateAction) => void; - t: (key: string) => string; -} - -const FundCreateModal: React.FC = ({ - fundCreateModalIsOpen, - hideCreateModal, - formState, - setFormState, - createFundHandler, - taxDeductible, - setTaxDeductible, - isDefault, - setIsDefault, - t, -}) => { - return ( - <> - - -

    {t('fundCreate')}

    - -
    - -
    - - {t('fundName')} - - setFormState({ - ...formState, - fundName: e.target.value, - }) - } - /> - - - {t('fundId')} - - setFormState({ - ...formState, - fundRef: e.target.value, - }) - } - /> - -
    - -
    - - setTaxDeductible(!taxDeductible)} - /> -
    -
    - -
    - - setIsDefault(!isDefault)} - /> -
    -
    -
    - -
    -
    -
    - - ); -}; -export default FundCreateModal; diff --git a/src/screens/OrganizationFunds/FundModal.test.tsx b/src/screens/OrganizationFunds/FundModal.test.tsx new file mode 100644 index 0000000000..c74b0434c3 --- /dev/null +++ b/src/screens/OrganizationFunds/FundModal.test.tsx @@ -0,0 +1,260 @@ +import React from 'react'; +import type { ApolloLink } from '@apollo/client'; +import { MockedProvider } from '@apollo/react-testing'; +import { LocalizationProvider } from '@mui/x-date-pickers'; +import type { RenderResult } from '@testing-library/react'; +import { + cleanup, + fireEvent, + render, + screen, + waitFor, +} from '@testing-library/react'; +import { I18nextProvider } from 'react-i18next'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; +import { store } from 'state/store'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import i18nForTest from '../../utils/i18nForTest'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import { toast } from 'react-toastify'; +import { MOCKS, MOCKS_ERROR } from './OrganizationFundsMocks'; +import type { InterfaceFundModal } from './FundModal'; +import FundModal from './FundModal'; + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + error: jest.fn(), + }, +})); + +const link1 = new StaticMockLink(MOCKS); +const link2 = new StaticMockLink(MOCKS_ERROR); +const translations = JSON.parse( + JSON.stringify(i18nForTest.getDataByLanguage('en')?.translation.funds), +); + +const fundProps: InterfaceFundModal[] = [ + { + isOpen: true, + hide: jest.fn(), + fund: { + _id: 'fundId', + name: 'Fund 1', + refrenceNumber: '1111', + taxDeductible: true, + isArchived: false, + isDefault: false, + createdAt: '2024-06-22', + organizationId: 'orgId', + creator: { + _id: 'creatorId1', + firstName: 'John', + lastName: 'Doe', + }, + }, + refetchFunds: jest.fn(), + orgId: 'orgId', + mode: 'create', + }, + { + isOpen: true, + hide: jest.fn(), + fund: { + _id: 'fundId', + name: 'Fund 1', + refrenceNumber: '1111', + taxDeductible: true, + isArchived: false, + isDefault: false, + createdAt: '2024-06-22', + organizationId: 'orgId', + creator: { + _id: 'creatorId1', + firstName: 'John', + lastName: 'Doe', + }, + }, + refetchFunds: jest.fn(), + orgId: 'orgId', + mode: 'edit', + }, +]; + +const renderFundModal = ( + link: ApolloLink, + props: InterfaceFundModal, +): RenderResult => { + return render( + + + + + + + + + + + , + ); +}; + +describe('PledgeModal', () => { + afterEach(() => { + cleanup(); + }); + + it('should populate form fields with correct values in edit mode', async () => { + renderFundModal(link1, fundProps[1]); + await waitFor(() => + expect( + screen.getAllByText(translations.fundUpdate)[0], + ).toBeInTheDocument(), + ); + expect(screen.getByLabelText(translations.fundName)).toHaveValue('Fund 1'); + expect(screen.getByLabelText(translations.fundId)).toHaveValue('1111'); + expect(screen.getByTestId('setTaxDeductibleSwitch')).toBeChecked(); + expect(screen.getByTestId('setDefaultSwitch')).not.toBeChecked(); + expect(screen.getByTestId('archivedSwitch')).not.toBeChecked(); + }); + + it('should update Fund Name when input value changes', async () => { + renderFundModal(link1, fundProps[1]); + const fundNameInput = screen.getByLabelText(translations.fundName); + expect(fundNameInput).toHaveValue('Fund 1'); + fireEvent.change(fundNameInput, { target: { value: 'Fund 2' } }); + expect(fundNameInput).toHaveValue('Fund 2'); + }); + + it('should update Fund Reference ID when input value changes', async () => { + renderFundModal(link1, fundProps[1]); + const fundIdInput = screen.getByLabelText(translations.fundId); + expect(fundIdInput).toHaveValue('1111'); + fireEvent.change(fundIdInput, { target: { value: '2222' } }); + expect(fundIdInput).toHaveValue('2222'); + }); + + it('should update Tax Deductible Switch when input value changes', async () => { + renderFundModal(link1, fundProps[1]); + const taxDeductibleSwitch = screen.getByTestId('setTaxDeductibleSwitch'); + expect(taxDeductibleSwitch).toBeChecked(); + fireEvent.click(taxDeductibleSwitch); + expect(taxDeductibleSwitch).not.toBeChecked(); + }); + + it('should update Tax Default switch when input value changes', async () => { + renderFundModal(link1, fundProps[1]); + const defaultSwitch = screen.getByTestId('setDefaultSwitch'); + expect(defaultSwitch).not.toBeChecked(); + fireEvent.click(defaultSwitch); + expect(defaultSwitch).toBeChecked(); + }); + + it('should update Tax isArchived switch when input value changes', async () => { + renderFundModal(link1, fundProps[1]); + const archivedSwitch = screen.getByTestId('archivedSwitch'); + expect(archivedSwitch).not.toBeChecked(); + fireEvent.click(archivedSwitch); + expect(archivedSwitch).toBeChecked(); + }); + + it('should create fund', async () => { + renderFundModal(link1, fundProps[0]); + + const fundNameInput = screen.getByLabelText(translations.fundName); + fireEvent.change(fundNameInput, { target: { value: 'Fund 2' } }); + + const fundIdInput = screen.getByLabelText(translations.fundId); + fireEvent.change(fundIdInput, { target: { value: '2222' } }); + + const taxDeductibleSwitch = screen.getByTestId('setTaxDeductibleSwitch'); + fireEvent.click(taxDeductibleSwitch); + + const defaultSwitch = screen.getByTestId('setDefaultSwitch'); + fireEvent.click(defaultSwitch); + + fireEvent.click(screen.getByTestId('createFundFormSubmitBtn')); + + await waitFor(() => { + expect(toast.success).toHaveBeenCalledWith(translations.fundCreated); + expect(fundProps[0].refetchFunds).toHaveBeenCalled(); + expect(fundProps[0].hide).toHaveBeenCalled(); + }); + }); + + it('should update fund', async () => { + renderFundModal(link1, fundProps[1]); + + const fundNameInput = screen.getByLabelText(translations.fundName); + fireEvent.change(fundNameInput, { target: { value: 'Fund 2' } }); + + const fundIdInput = screen.getByLabelText(translations.fundId); + fireEvent.change(fundIdInput, { target: { value: '2222' } }); + + const taxDeductibleSwitch = screen.getByTestId('setTaxDeductibleSwitch'); + fireEvent.click(taxDeductibleSwitch); + + const defaultSwitch = screen.getByTestId('setDefaultSwitch'); + fireEvent.click(defaultSwitch); + + const archivedSwitch = screen.getByTestId('archivedSwitch'); + fireEvent.click(archivedSwitch); + + fireEvent.click(screen.getByTestId('createFundFormSubmitBtn')); + + await waitFor(() => { + expect(toast.success).toHaveBeenCalledWith(translations.fundUpdated); + expect(fundProps[1].refetchFunds).toHaveBeenCalled(); + expect(fundProps[1].hide).toHaveBeenCalled(); + }); + }); + + it('Error: should create fund', async () => { + renderFundModal(link2, fundProps[0]); + + const fundNameInput = screen.getByLabelText(translations.fundName); + fireEvent.change(fundNameInput, { target: { value: 'Fund 2' } }); + + const fundIdInput = screen.getByLabelText(translations.fundId); + fireEvent.change(fundIdInput, { target: { value: '2222' } }); + + const taxDeductibleSwitch = screen.getByTestId('setTaxDeductibleSwitch'); + fireEvent.click(taxDeductibleSwitch); + + const defaultSwitch = screen.getByTestId('setDefaultSwitch'); + fireEvent.click(defaultSwitch); + + fireEvent.click(screen.getByTestId('createFundFormSubmitBtn')); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalledWith('Mock graphql error'); + }); + }); + + it('Error: should update fund', async () => { + renderFundModal(link2, fundProps[1]); + + const fundNameInput = screen.getByLabelText(translations.fundName); + fireEvent.change(fundNameInput, { target: { value: 'Fund 2' } }); + + const fundIdInput = screen.getByLabelText(translations.fundId); + fireEvent.change(fundIdInput, { target: { value: '2222' } }); + + const taxDeductibleSwitch = screen.getByTestId('setTaxDeductibleSwitch'); + fireEvent.click(taxDeductibleSwitch); + + const defaultSwitch = screen.getByTestId('setDefaultSwitch'); + fireEvent.click(defaultSwitch); + + const archivedSwitch = screen.getByTestId('archivedSwitch'); + fireEvent.click(archivedSwitch); + + fireEvent.click(screen.getByTestId('createFundFormSubmitBtn')); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalledWith('Mock graphql error'); + }); + }); +}); diff --git a/src/screens/OrganizationFunds/FundModal.tsx b/src/screens/OrganizationFunds/FundModal.tsx new file mode 100644 index 0000000000..0f112cba9b --- /dev/null +++ b/src/screens/OrganizationFunds/FundModal.tsx @@ -0,0 +1,286 @@ +import React, { useEffect, useState } from 'react'; +import type { ChangeEvent } from 'react'; +import { Button, Form, Modal } from 'react-bootstrap'; +import type { InterfaceCreateFund, InterfaceFundInfo } from 'utils/interfaces'; +import styles from './OrganizationFunds.module.css'; +import { useTranslation } from 'react-i18next'; +import { useMutation } from '@apollo/client'; +import { + CREATE_FUND_MUTATION, + UPDATE_FUND_MUTATION, +} from 'GraphQl/Mutations/FundMutation'; +import { toast } from 'react-toastify'; +import { FormControl, TextField } from '@mui/material'; + +export interface InterfaceFundModal { + isOpen: boolean; + hide: () => void; + refetchFunds: () => void; + fund: InterfaceFundInfo | null; + orgId: string; + mode: 'create' | 'edit'; +} +/** + * `FundModal` component provides a modal dialog for creating or editing a fund. + * It allows users to input fund details and submit them to the server. + * + * This component handles both the creation of new funds and the editing of existing funds, + * based on the `mode` prop. It displays a form with fields for the fund's name, description, + * and other relevant details. Upon submission, it interacts with the GraphQL API to save + * or update the fund details and triggers a refetch of the fund data. + * + * ### Props + * - `isOpen`: A boolean indicating whether the modal is open or closed. + * - `hide`: A function to close the modal. + * - `refetchFunds`: A function to refetch the fund list after a successful operation. + * - `fund`: The current fund object being edited or `null` if creating a new fund. + * - `orgId`: The ID of the organization to which the fund belongs. + * - `mode`: The mode of the modal, either 'edit' or 'create'. + * + * ### State + * - `name`: The name of the fund. + * - `description`: The description of the fund. + * - `amount`: The amount associated with the fund. + * - `status`: The status of the fund (e.g., active, archived). + * + * ### Methods + * - `handleSubmit()`: Handles form submission, creates or updates the fund, and triggers a refetch of the fund list. + * - `handleChange(event: React.ChangeEvent)`: Updates the state based on user input. + * + * @returns The rendered modal dialog. + */ +const FundModal: React.FC = ({ + isOpen, + hide, + refetchFunds, + fund, + orgId, + mode, +}) => { + const { t } = useTranslation('translation', { + keyPrefix: 'funds', + }); + + const [formState, setFormState] = useState({ + fundName: fund?.name ?? '', + fundRef: fund?.refrenceNumber ?? '', + isDefault: fund?.isDefault ?? false, + taxDeductible: fund?.taxDeductible ?? false, + isArchived: fund?.isArchived ?? false, + }); + + useEffect(() => { + setFormState({ + fundName: fund?.name ?? '', + fundRef: fund?.refrenceNumber ?? '', + isDefault: fund?.isDefault ?? false, + taxDeductible: fund?.taxDeductible ?? false, + isArchived: fund?.isArchived ?? false, + }); + }, [fund]); + + const [createFund] = useMutation(CREATE_FUND_MUTATION); + const [updateFund] = useMutation(UPDATE_FUND_MUTATION); + + const createFundHandler = async ( + e: ChangeEvent, + ): Promise => { + e.preventDefault(); + const { fundName, fundRef, isDefault, taxDeductible, isArchived } = + formState; + try { + await createFund({ + variables: { + name: fundName, + refrenceNumber: fundRef, + organizationId: orgId, + taxDeductible, + isArchived, + isDefault, + }, + }); + + setFormState({ + fundName: '', + fundRef: '', + isDefault: false, + taxDeductible: false, + isArchived: false, + }); + toast.success(t('fundCreated') as string); + refetchFunds(); + hide(); + } catch (error: unknown) { + toast.error((error as Error).message); + } + }; + + /*istanbul ignore next*/ + const updateFundHandler = async ( + e: ChangeEvent, + ): Promise => { + e.preventDefault(); + const { fundName, fundRef, taxDeductible, isArchived, isDefault } = + formState; + try { + const updatedFields: { [key: string]: string | boolean } = {}; + if (fundName != fund?.name) { + updatedFields.name = fundName; + } + if (fundRef != fund?.refrenceNumber) { + updatedFields.refrenceNumber = fundRef; + } + if (taxDeductible != fund?.taxDeductible) { + updatedFields.taxDeductible = taxDeductible; + } + if (isArchived != fund?.isArchived) { + updatedFields.isArchived = isArchived; + } + if (isDefault != fund?.isDefault) { + updatedFields.isDefault = isDefault; + } + + await updateFund({ + variables: { + id: fund?._id, + ...updatedFields, + }, + }); + setFormState({ + fundName: '', + fundRef: '', + isDefault: false, + taxDeductible: false, + isArchived: false, + }); + refetchFunds(); + hide(); + toast.success(t('fundUpdated') as string); + } catch (error: unknown) { + if (error instanceof Error) { + toast.error(error.message); + } + } + }; + + return ( + <> + + +

    + {t(mode === 'create' ? 'fundCreate' : 'fundUpdate')} +

    + +
    + +
    + + + + setFormState({ + ...formState, + fundName: e.target.value, + }) + } + /> + + + + + + setFormState({ + ...formState, + fundRef: e.target.value, + }) + } + /> + + + +
    + + + + setFormState({ + ...formState, + taxDeductible: !formState.taxDeductible, + }) + } + /> + + + + + setFormState({ + ...formState, + isDefault: !formState.isDefault, + }) + } + /> + + {mode === 'edit' && ( + + + + setFormState({ + ...formState, + isArchived: !formState.isArchived, + }) + } + /> + + )} +
    + +
    +
    +
    + + ); +}; +export default FundModal; diff --git a/src/screens/OrganizationFunds/FundUpdateModal.tsx b/src/screens/OrganizationFunds/FundUpdateModal.tsx deleted file mode 100644 index 2a351a1c8c..0000000000 --- a/src/screens/OrganizationFunds/FundUpdateModal.tsx +++ /dev/null @@ -1,155 +0,0 @@ -import type { ChangeEvent } from 'react'; -import React from 'react'; -import { Button, Form, Modal } from 'react-bootstrap'; -import type { InterfaceCreateFund } from 'utils/interfaces'; -import styles from './OrganizationFunds.module.css'; - -interface InterfaceFundUpdateModal { - fundUpdateModalIsOpen: boolean; - hideUpdateModal: () => void; - formState: InterfaceCreateFund; - setFormState: (state: React.SetStateAction) => void; - updateFundHandler: (e: ChangeEvent) => Promise; - taxDeductible: boolean; - setTaxDeductible: (state: React.SetStateAction) => void; - isArchived: boolean; - deleteFundHandler: () => Promise; - setIsArchived: (state: React.SetStateAction) => void; - isDefault: boolean; - setIsDefault: (state: React.SetStateAction) => void; - t: (key: string) => string; -} - -const FundUpdateModal: React.FC = ({ - fundUpdateModalIsOpen, - hideUpdateModal, - formState, - setFormState, - updateFundHandler, - taxDeductible, - setTaxDeductible, - isArchived, - deleteFundHandler, - setIsArchived, - isDefault, - setIsDefault, - t, -}) => { - return ( - <> - - -

    {t('manageFund')}

    - -
    - -
    - - {t('fundName')} - - setFormState({ - ...formState, - fundName: e.target.value, - }) - } - /> - - - {t('fundId')} - - setFormState({ - ...formState, - fundRef: e.target.value, - }) - } - /> - - -
    -
    - -
    - - setTaxDeductible(!taxDeductible)} - /> -
    -
    - -
    - - setIsDefault(!isDefault)} - /> -
    -
    -
    -
    - -
    - - setIsArchived(!isArchived)} - /> -
    -
    -
    -
    -
    - - -
    -
    -
    -
    - - ); -}; -export default FundUpdateModal; diff --git a/src/screens/OrganizationFunds/OrganizationFunds.module.css b/src/screens/OrganizationFunds/OrganizationFunds.module.css index 07e16ad0a8..aa9d89dfb1 100644 --- a/src/screens/OrganizationFunds/OrganizationFunds.module.css +++ b/src/screens/OrganizationFunds/OrganizationFunds.module.css @@ -21,24 +21,13 @@ border: 1px solid #31bb6b; position: relative; display: inline-block; - margin-top: 10px; - margin-bottom: 10px; color: #31bb6b; } -.createFundBtn { - margin-top: 10px; -} - .fundName { font-weight: 600; cursor: pointer; } -.fundModal { - max-width: 80vw; - margin-top: 2vh; - margin-left: 13vw; -} .modalHeader { border: none; @@ -49,12 +38,33 @@ color: var(--bs-emphasis-color); } +.fundModal { + max-width: 80vw; + margin-top: 2vh; + margin-left: 13vw; +} + .titlemodal { + color: #707070; font-weight: 600; - font-size: 25px; - margin-top: 1rem; + font-size: 32px; width: 65%; + margin-bottom: 0px; } + +.noOutline input { + outline: none; +} + +.modalCloseBtn { + width: 40px; + height: 40px; + padding: 1rem; + display: flex; + justify-content: center; + align-items: center; +} + .greenregbtn { margin: 1rem 0 0; margin-top: 15px; @@ -95,22 +105,12 @@ .btnsContainer { display: flex; - margin: 2.5rem 0 2.5rem 0; -} - -.btnsContainer .btnsBlock { - display: flex; -} - -.btnsContainer .btnsBlock div button { - display: flex; - margin-left: 1rem; - justify-content: center; - align-items: center; + margin: 2rem 0 2.5rem 0; } .btnsContainer .input { flex: 1; + min-width: 18rem; position: relative; } @@ -130,48 +130,13 @@ margin-bottom: 20px; } -@media (max-width: 1020px) { - .btnsContainer { - flex-direction: column; - margin: 1.5rem 0; - } - - .btnsContainer .btnsBlock { - margin: 1.5rem 0 0 0; - justify-content: space-between; - } - - .btnsContainer .btnsBlock div button { - margin: 0; - } - - .createFundBtn { - margin-top: 0; - } -} - -@media screen and (max-width: 575.5px) { - .mainpageright { - width: 98%; - } +.rowBackground { + background-color: var(--bs-white); + max-height: 120px; } -/* For mobile devices */ - -@media (max-width: 520px) { - .btnsContainer { - margin-bottom: 0; - } - - .btnsContainer .btnsBlock { - display: block; - margin-top: 1rem; - margin-right: 0; - } - - .btnsContainer .btnsBlock div button { - margin-bottom: 1rem; - margin-right: 0; - width: 100%; - } +.tableHeader { + background-color: var(--bs-primary); + color: var(--bs-white); + font-size: 1rem; } diff --git a/src/screens/OrganizationFunds/OrganizationFunds.test.tsx b/src/screens/OrganizationFunds/OrganizationFunds.test.tsx index 93be2c281c..c6983e1d6d 100644 --- a/src/screens/OrganizationFunds/OrganizationFunds.test.tsx +++ b/src/screens/OrganizationFunds/OrganizationFunds.test.tsx @@ -1,407 +1,244 @@ import React from 'react'; import { MockedProvider } from '@apollo/client/testing'; +import type { RenderResult } from '@testing-library/react'; import { - act, + cleanup, fireEvent, render, screen, waitFor, - waitForElementToBeRemoved, } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { I18nextProvider } from 'react-i18next'; import { Provider } from 'react-redux'; -import { BrowserRouter } from 'react-router-dom'; -import { toast } from 'react-toastify'; +import { MemoryRouter, Route, Routes } from 'react-router-dom'; import { store } from 'state/store'; import { StaticMockLink } from 'utils/StaticMockLink'; import i18nForTest from 'utils/i18nForTest'; import OrganizationFunds from './OrganizationFunds'; -import { - MOCKS, - MOCKS_ERROR_CREATE_FUND, - MOCKS_ERROR_ORGANIZATIONS_FUNDS, - MOCKS_ERROR_REMOVE_FUND, - MOCKS_ERROR_UPDATE_FUND, - NO_FUNDS, -} from './OrganizationFundsMocks'; -const mockNavigate = jest.fn(); -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useNavigate: () => mockNavigate, -})); +import { MOCKS, MOCKS_ERROR, NO_FUNDS } from './OrganizationFundsMocks'; +import type { ApolloLink } from '@apollo/client'; +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; + jest.mock('react-toastify', () => ({ toast: { success: jest.fn(), error: jest.fn(), }, })); -async function wait(ms = 100): Promise { - await act(() => { - return new Promise((resolve) => { - setTimeout(resolve, ms); - }); - }); -} + const link1 = new StaticMockLink(MOCKS, true); -const link2 = new StaticMockLink(MOCKS_ERROR_ORGANIZATIONS_FUNDS, true); -const link3 = new StaticMockLink(MOCKS_ERROR_CREATE_FUND, true); -const link4 = new StaticMockLink(MOCKS_ERROR_UPDATE_FUND, true); -const link5 = new StaticMockLink(MOCKS_ERROR_REMOVE_FUND, true); -const link6 = new StaticMockLink(NO_FUNDS, true); +const link2 = new StaticMockLink(MOCKS_ERROR, true); +const link3 = new StaticMockLink(NO_FUNDS, true); const translations = JSON.parse( JSON.stringify(i18nForTest.getDataByLanguage('en')?.translation.funds), ); -describe('Testing OrganizationFunds screen', () => { - const formData = { - fundName: 'Test Fund', - fundRef: '1', - }; - it("loads the OrganizationFunds screen and it's components", async () => { - const { getByText } = render( - + +const renderOrganizationFunds = (link: ApolloLink): RenderResult => { + return render( + + - + - {} + + } + /> +
    } + /> +
    } + /> + - + - , - ); - await wait(); - await waitFor(() => { - expect(getByText(translations.createFund)).toBeInTheDocument(); - }); + + , + ); +}; + +describe('OrganizationFunds Screen =>', () => { + beforeEach(() => { + jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: 'orgId' }), + })); }); - it("renders the OrganizationFunds screen and it's components with error", async () => { - const { queryByText } = render( - - - - - {} - - - - , - ); - await wait(); - await waitFor(() => { - expect(queryByText(translations.createFund)).not.toBeInTheDocument(); - }); + + afterEach(() => { + jest.clearAllMocks(); }); - it('renders the Error component', async () => { - render( - - - - - {} - - - - , - ); - await wait(); - await waitFor(() => { - expect(screen.getByTestId('errorMsg')).toBeInTheDocument(); - }); + + afterEach(() => { + cleanup(); }); - it('renders the funds component based on fund type', async () => { - render( - - - - - {} - - - - , - ); - await wait(); - await waitFor(() => { - expect(screen.getAllByTestId('fundtype')[0]).toBeInTheDocument(); - }); + + it('should render the Campaign Pledge screen', async () => { + renderOrganizationFunds(link1); await waitFor(() => { - expect(screen.getAllByTestId('fundtype')[0]).toHaveTextContent( - translations.nonArchive, - ); + expect(screen.getByTestId('searchByName')).toBeInTheDocument(); }); - expect(screen.getAllByTestId('fundtype')[1]).toHaveTextContent( - translations.archived, - ); }); - it("opens and closes the 'Create Fund' modal", async () => { + + it('should redirect to fallback URL if URL params are undefined', async () => { render( - - + + - {} + + } /> +
    } + /> + - - + + , ); - await wait(); await waitFor(() => { - expect(screen.getByTestId('createFundBtn')).toBeInTheDocument(); + expect(screen.getByTestId('paramsError')).toBeInTheDocument(); }); - userEvent.click(screen.getByTestId('createFundBtn')); - await waitFor(() => { - return expect( - screen.findByTestId('createFundModalCloseBtn'), - ).resolves.toBeInTheDocument(); - }); - userEvent.click(screen.getByTestId('setTaxDeductibleSwitch')); - userEvent.click(screen.getByTestId('setDefaultSwitch')); - userEvent.click(screen.getByTestId('createFundModalCloseBtn')); - await waitForElementToBeRemoved(() => - screen.queryByTestId('createFundModalCloseBtn'), - ); }); - it('noFunds to be in the document', async () => { - render( - - - - - {} - - - - , + + it('open and close Create Fund modal', async () => { + renderOrganizationFunds(link1); + + const createFundBtn = await screen.findByTestId('createFundBtn'); + expect(createFundBtn).toBeInTheDocument(); + userEvent.click(createFundBtn); + + await waitFor(() => + expect(screen.getAllByText(translations.fundCreate)).toHaveLength(3), ); - await wait(); - await waitFor(() => { - expect(screen.getByText(translations.noFundsFound)).toBeInTheDocument(); - }); - }); - it('creates a new fund', async () => { - render( - - - - - {} - - - - , + userEvent.click(screen.getByTestId('fundModalCloseBtn')); + await waitFor(() => + expect(screen.queryByTestId('fundModalCloseBtn')).toBeNull(), ); - await wait(); - await waitFor(() => { - expect(screen.getByTestId('createFundBtn')).toBeInTheDocument(); - }); - userEvent.click(screen.getByTestId('createFundBtn')); + }); + + it('open and close update fund modal', async () => { + renderOrganizationFunds(link1); + await waitFor(() => { - return expect( - screen.findByTestId('createFundModalCloseBtn'), - ).resolves.toBeInTheDocument(); + expect(screen.getByTestId('searchByName')).toBeInTheDocument(); }); - userEvent.type( - screen.getByPlaceholderText(translations.enterfundName), - formData.fundName, + + const editFundBtn = await screen.findAllByTestId('editFundBtn'); + await waitFor(() => expect(editFundBtn[0]).toBeInTheDocument()); + userEvent.click(editFundBtn[0]); + + await waitFor(() => + expect( + screen.getAllByText(translations.fundUpdate)[0], + ).toBeInTheDocument(), ); - userEvent.type( - screen.getByPlaceholderText(translations.enterfundId), - formData.fundRef, + userEvent.click(screen.getByTestId('fundModalCloseBtn')); + await waitFor(() => + expect(screen.queryByTestId('fundModalCloseBtn')).toBeNull(), ); - userEvent.click(screen.getByTestId('setTaxDeductibleSwitch')); - userEvent.click(screen.getByTestId('setDefaultSwitch')); - userEvent.click(screen.getByTestId('setTaxDeductibleSwitch')); - userEvent.click(screen.getByTestId('setDefaultSwitch')); - await wait(); - userEvent.click(screen.getByTestId('createFundFormSubmitBtn')); + }); - await waitFor(() => { - expect(toast.success).toBeCalledWith(translations.fundCreated); + it('Search the Funds list by name', async () => { + renderOrganizationFunds(link1); + const searchField = await screen.findByTestId('searchByName'); + fireEvent.change(searchField, { + target: { value: '2' }, }); - }); - it('updates fund successfully', async () => { - render( - - - - - {} - - - - , - ); - await wait(); - userEvent.click(screen.getAllByTestId('editFundBtn')[0]); - await wait(); - userEvent.clear(screen.getByTestId('fundNameInput')); - userEvent.clear(screen.getByTestId('fundIdInput')); - userEvent.type(screen.getByTestId('fundNameInput'), 'Test Fund'); - userEvent.type(screen.getByTestId('fundIdInput'), '1'); - expect(screen.getByTestId('taxDeductibleSwitch')).toBeInTheDocument(); - expect(screen.getByTestId('defaultSwitch')).toBeInTheDocument(); - expect(screen.getByTestId('archivedSwitch')).toBeInTheDocument(); - expect(screen.getByTestId('updateFormBtn')).toBeInTheDocument(); - userEvent.click(screen.getByTestId('taxDeductibleSwitch')); - userEvent.click(screen.getByTestId('defaultSwitch')); - userEvent.click(screen.getByTestId('archivedSwitch')); - await wait(); - userEvent.click(screen.getByTestId('updateFormBtn')); - await wait(); + await waitFor(() => { - expect(toast.success).toBeCalledWith(translations.fundUpdated); + expect(screen.getByText('Fund 2')).toBeInTheDocument(); + expect(screen.queryByText('Fund 1')).toBeNull(); }); }); - it('toast error on unsuccessful fund creation', async () => { - render( - - - - - {} - - - - , - ); - await wait(); - await waitFor(() => { - expect(screen.getByTestId('createFundBtn')).toBeInTheDocument(); - }); - userEvent.click(screen.getByTestId('createFundBtn')); - await waitFor(() => { - return expect( - screen.findByTestId('createFundModalCloseBtn'), - ).resolves.toBeInTheDocument(); - }); - userEvent.type( - screen.getByPlaceholderText(translations.enterfundName), - formData.fundName, - ); - userEvent.type( - screen.getByPlaceholderText(translations.enterfundId), - formData.fundRef, - ); - userEvent.click(screen.getByTestId('createFundFormSubmitBtn')); + it('should render the Fund screen with error', async () => { + renderOrganizationFunds(link2); await waitFor(() => { - expect(toast.error).toHaveBeenCalled(); + expect(screen.getByTestId('errorMsg')).toBeInTheDocument(); }); }); - it('toast error on unsuccessful fund update', async () => { - render( - - - - - {} - - - - , + + it('renders the empty fund component', async () => { + renderOrganizationFunds(link3); + await waitFor(() => + expect(screen.getByText(translations.noFundsFound)).toBeInTheDocument(), ); - await wait(); - await waitFor(() => { - expect(screen.getAllByTestId('editFundBtn')[0]).toBeInTheDocument(); - }); - userEvent.click(screen.getAllByTestId('editFundBtn')[0]); + }); + + it('Sort the Pledges list by Latest created Date', async () => { + renderOrganizationFunds(link1); + + const sortBtn = await screen.findByTestId('filter'); + expect(sortBtn).toBeInTheDocument(); + + fireEvent.click(sortBtn); + fireEvent.click(screen.getByTestId('createdAt_DESC')); + await waitFor(() => { - return expect( - screen.findByTestId('editFundModalCloseBtn'), - ).resolves.toBeInTheDocument(); + expect(screen.getByText('Fund 1')).toBeInTheDocument(); + expect(screen.queryByText('Fund 2')).toBeInTheDocument(); }); - userEvent.type( - screen.getByPlaceholderText(translations.enterfundName), - 'Test Fund Updated', - ); - userEvent.click(screen.getByTestId('updateFormBtn')); await waitFor(() => { - expect(toast.error).toHaveBeenCalled(); + expect(screen.getAllByTestId('createdOn')[0]).toHaveTextContent( + '22/06/2024', + ); }); }); - it('redirects to campaign screen when clicked on fund name', async () => { - render( - - - - - {} - - - - , - ); - await wait(); + + it('Sort the Pledges list by Earliest created Date', async () => { + renderOrganizationFunds(link1); + + const sortBtn = await screen.findByTestId('filter'); + expect(sortBtn).toBeInTheDocument(); + + fireEvent.click(sortBtn); + fireEvent.click(screen.getByTestId('createdAt_ASC')); + await waitFor(() => { - expect(screen.getAllByTestId('fundName')[0]).toBeInTheDocument(); + expect(screen.getByText('Fund 1')).toBeInTheDocument(); + expect(screen.queryByText('Fund 2')).toBeInTheDocument(); }); - userEvent.click(screen.getAllByTestId('fundName')[0]); + await waitFor(() => { - expect(mockNavigate).toBeCalledWith('/orgfundcampaign/undefined/1'); + expect(screen.getAllByTestId('createdOn')[0]).toHaveTextContent( + '21/06/2024', + ); }); }); - it('delete fund succesfully', async () => { - render( - - - - - {} - - - - , - ); - await wait(); - userEvent.click(screen.getAllByTestId('editFundBtn')[0]); - await wait(); - userEvent.click(screen.getByTestId('fundDeleteModalDeleteBtn')); + + it('Click on Fund Name', async () => { + renderOrganizationFunds(link1); + + const fundName = await screen.findAllByTestId('fundName'); + expect(fundName[0]).toBeInTheDocument(); + fireEvent.click(fundName[0]); + await waitFor(() => { - expect(toast.success).toBeCalledWith(translations.fundDeleted); + expect(screen.getByTestId('campaignScreen')).toBeInTheDocument(); }); }); - it('throws error on unsuccessful fund deletion', async () => { - render( - - - - - {} - - - - , - ); - await wait(); - userEvent.click(screen.getAllByTestId('editFundBtn')[0]); - await wait(); - userEvent.click(screen.getByTestId('fundDeleteModalDeleteBtn')); + + it('Click on View Campaign', async () => { + renderOrganizationFunds(link1); + + const viewBtn = await screen.findAllByTestId('viewBtn'); + expect(viewBtn[0]).toBeInTheDocument(); + fireEvent.click(viewBtn[0]); + await waitFor(() => { - expect(toast.error).toBeCalled(); + expect(screen.getByTestId('campaignScreen')).toBeInTheDocument(); }); }); - it('search funds by name', async () => { - render( - - - - - {} - - - - , - ); - await wait(); - userEvent.click(screen.getAllByTestId('editFundBtn')[0]); - await wait(); - userEvent.click(screen.getByTestId('editFundModalCloseBtn')); - await wait(); - userEvent.type(screen.getByTestId('searchFullName'), 'Funndds'); - await wait(); - userEvent.click(screen.getByTestId('searchBtn')); - }); }); diff --git a/src/screens/OrganizationFunds/OrganizationFunds.tsx b/src/screens/OrganizationFunds/OrganizationFunds.tsx index b0846c8c0a..29ffb0d865 100644 --- a/src/screens/OrganizationFunds/OrganizationFunds.tsx +++ b/src/screens/OrganizationFunds/OrganizationFunds.tsx @@ -1,77 +1,109 @@ -/*eslint-disable*/ -import { useMutation, useQuery } from '@apollo/client'; -import { Search, WarningAmberRounded } from '@mui/icons-material'; +import { useQuery } from '@apollo/client'; +import { Search, Sort, WarningAmberRounded } from '@mui/icons-material'; +import { Stack } from '@mui/material'; import { - CREATE_FUND_MUTATION, - REMOVE_FUND_MUTATION, - UPDATE_FUND_MUTATION, -} from 'GraphQl/Mutations/FundMutation'; -import Loader from 'components/Loader/Loader'; -import { useState, type ChangeEvent } from 'react'; -import { Button, Col, Dropdown, Form, Row } from 'react-bootstrap'; + DataGrid, + type GridCellParams, + type GridColDef, +} from '@mui/x-data-grid'; +import { Button, Dropdown, Form } from 'react-bootstrap'; import { useTranslation } from 'react-i18next'; -import { useNavigate, useParams } from 'react-router-dom'; -import { toast } from 'react-toastify'; -import type { - InterfaceCreateFund, - InterfaceFundInfo, - InterfaceQueryOrganizationFunds, -} from 'utils/interfaces'; -import FundCreateModal from './FundCreateModal'; -import FundUpdateModal from './FundUpdateModal'; -import FilterAltOutlinedIcon from '@mui/icons-material/FilterAltOutlined'; -import styles from './OrganizationFunds.module.css'; -import { - Paper, - Table, - TableBody, - TableCell, - TableContainer, - TableHead, - TableRow, - styled, - tableCellClasses, -} from '@mui/material'; +import { Navigate, useNavigate, useParams } from 'react-router-dom'; +import React, { useCallback, useMemo, useState } from 'react'; import dayjs from 'dayjs'; +import Loader from 'components/Loader/Loader'; +import FundModal from './FundModal'; import { FUND_LIST } from 'GraphQl/Queries/fundQueries'; +import styles from './OrganizationFunds.module.css'; +import type { InterfaceFundInfo } from 'utils/interfaces'; -const StyledTableCell = styled(TableCell)(({ theme }) => ({ - [`&.${tableCellClasses.head}`]: { - backgroundColor: ['#31bb6b', '!important'], - color: theme.palette.common.white, +const dataGridStyle = { + '&.MuiDataGrid-root .MuiDataGrid-cell:focus-within': { + outline: 'none !important', }, - [`&.${tableCellClasses.body}`]: { - fontSize: 14, + '&.MuiDataGrid-root .MuiDataGrid-columnHeader:focus-within': { + outline: 'none', }, -})); - -const StyledTableRow = styled(TableRow)(() => ({ - '&:last-child td, &:last-child th': { - border: 0, + '& .MuiDataGrid-row:hover': { + backgroundColor: 'transparent', + }, + '& .MuiDataGrid-row.Mui-hovered': { + backgroundColor: 'transparent', }, -})); + '& .MuiDataGrid-root': { + borderRadius: '0.5rem', + }, + '& .MuiDataGrid-main': { + borderRadius: '0.5rem', + }, +}; +/** + * `organizationFunds` component displays a list of funds for a specific organization, + * allowing users to search, sort, view and edit funds. + * + * This component utilizes the `DataGrid` from Material-UI to present the list of funds in a tabular format, + * and includes functionality for filtering and sorting. It also handles the opening and closing of modals + * for creating and editing. + * + * It includes: + * - A search input field to filter funds by name. + * - A dropdown menu to sort funds by creation date. + * - A button to create a new fund. + * - A table to display the list of funds with columns for fund details and actions. + * - Modals for creating and editing funds. + * + * ### GraphQL Queries + * - `FUND_LIST`: Fetches a list of funds for the given organization, filtered and sorted based on the provided parameters. + * + * ### Props + * - `orgId`: The ID of the organization whose funds are being managed. + * + * ### State + * - `fund`: The currently selected fund for editing or deletion. + * - `searchTerm`: The current search term used for filtering funds. + * - `sortBy`: The current sorting order for funds. + * - `modalState`: The state of the modals (edit/create). + * - `fundModalMode`: The mode of the fund modal (edit or create). + * + * ### Methods + * - `handleOpenModal(fund: InterfaceFundInfo | null, mode: 'edit' | 'create')`: Opens the fund modal with the given fund and mode. + * - `handleClick(fundId: string)`: Navigates to the campaign page for the specified fund. + * + * @returns The rendered component. + */ const organizationFunds = (): JSX.Element => { const { t } = useTranslation('translation', { keyPrefix: 'funds', }); const { t: tCommon } = useTranslation('common'); - const { orgId: currentUrl } = useParams(); + const { orgId } = useParams(); const navigate = useNavigate(); - const [fundCreateModalIsOpen, setFundCreateModalIsOpen] = - useState(false); - const [fundUpdateModalIsOpen, setFundUpdateModalIsOpen] = - useState(false); - const [taxDeductible, setTaxDeductible] = useState(true); - const [isArchived, setIsArchived] = useState(false); - const [isDefault, setIsDefault] = useState(false); + if (!orgId) { + return ; + } + const [fund, setFund] = useState(null); - const [formState, setFormState] = useState({ - fundName: '', - fundRef: '', - }); + const [searchTerm, setSearchTerm] = useState(''); + const [sortBy, setSortBy] = useState<'createdAt_ASC' | 'createdAt_DESC'>( + 'createdAt_DESC', + ); + + const [modalState, setModalState] = useState(false); + const [fundModalMode, setFundModalMode] = useState<'edit' | 'create'>( + 'create', + ); + + const handleOpenModal = useCallback( + (fund: InterfaceFundInfo | null, mode: 'edit' | 'create'): void => { + setFund(fund); + setFundModalMode(mode); + setModalState(true); + }, + [], + ); const { data: fundData, @@ -80,144 +112,23 @@ const organizationFunds = (): JSX.Element => { refetch: refetchFunds, }: { data?: { - fundsByOrganization: InterfaceQueryOrganizationFunds[]; + fundsByOrganization: InterfaceFundInfo[]; }; loading: boolean; error?: Error | undefined; - refetch: any; + refetch: () => void; } = useQuery(FUND_LIST, { variables: { - organizationId: currentUrl, + organizationId: orgId, + filter: searchTerm, + orderBy: sortBy, }, }); - const [fullName, setFullName] = useState(''); - const handleSearch = (): void => { - refetchFunds({ organizationId: currentUrl, filter: fullName }); - }; - - const [createFund] = useMutation(CREATE_FUND_MUTATION); - const [updateFund] = useMutation(UPDATE_FUND_MUTATION); - const [deleteFund] = useMutation(REMOVE_FUND_MUTATION); + const funds = useMemo(() => fundData?.fundsByOrganization ?? [], [fundData]); - const showCreateModal = (): void => { - setFundCreateModalIsOpen(!fundCreateModalIsOpen); - }; - const hideCreateModal = (): void => { - setFundCreateModalIsOpen(!fundCreateModalIsOpen); - }; - const showUpdateModal = (): void => { - setFundUpdateModalIsOpen(!fundUpdateModalIsOpen); - }; - const hideUpdateModal = (): void => { - setFundUpdateModalIsOpen(!fundUpdateModalIsOpen); - }; - const toggleDeleteModal = (): void => { - setFundUpdateModalIsOpen(!fundUpdateModalIsOpen); - }; - const handleEditClick = (fund: InterfaceFundInfo): void => { - setFormState({ - fundName: fund.name, - fundRef: fund.refrenceNumber, - }); - setTaxDeductible(fund.taxDeductible); - setIsArchived(fund.isArchived); - setIsDefault(fund.isDefault); - setFund(fund); - showUpdateModal(); - }; - const createFundHandler = async ( - e: ChangeEvent, - ): Promise => { - e.preventDefault(); - try { - await createFund({ - variables: { - name: formState.fundName, - refrenceNumber: formState.fundRef, - organizationId: currentUrl, - taxDeductible: taxDeductible, - isArchived: isArchived, - isDefault: isDefault, - }, - }); - - setFormState({ - fundName: '', - fundRef: '', - }); - toast.success(t('fundCreated')); - refetchFunds(); - hideCreateModal(); - } catch (error: unknown) { - if (error instanceof Error) { - toast.error(error.message); - console.log(error.message); - } - } - }; - const updateFundHandler = async ( - e: ChangeEvent, - ): Promise => { - e.preventDefault(); - try { - const updatedFields: { [key: string]: any } = {}; - if (formState.fundName != fund?.name) { - updatedFields.name = formState.fundName; - } - if (formState.fundRef != fund?.refrenceNumber) { - updatedFields.refrenceNumber = formState.fundRef; - } - if (taxDeductible != fund?.taxDeductible) { - updatedFields.taxDeductible = taxDeductible; - } - if (isArchived != fund?.isArchived) { - updatedFields.isArchived = isArchived; - } - if (isDefault != fund?.isDefault) { - updatedFields.isDefault = isDefault; - } - - await updateFund({ - variables: { - id: fund?._id, - ...updatedFields, - }, - }); - setFormState({ - fundName: '', - fundRef: '', - }); - refetchFunds(); - hideUpdateModal(); - toast.success(t('fundUpdated')); - } catch (error: unknown) { - if (error instanceof Error) { - toast.error(error.message); - console.log(error.message); - } - } - }; - const deleteFundHandler = async (): Promise => { - try { - await deleteFund({ - variables: { - id: fund?._id, - }, - }); - refetchFunds(); - toggleDeleteModal(); - toast.success(t('fundDeleted')); - } catch (error: unknown) { - if (error instanceof Error) { - toast.error(error.message); - console.log(error.message); - } - } - }; - - const handleClick = (fundId: String) => { - navigate(`/orgfundcampaign/${currentUrl}/${fundId}`); + const handleClick = (fundId: string): void => { + navigate(`/orgfundcampaign/${orgId}/${fundId}`); }; if (fundLoading) { @@ -238,187 +149,234 @@ const organizationFunds = (): JSX.Element => { ); } + const columns: GridColDef[] = [ + { + field: 'id', + headerName: 'Sr. No.', + flex: 1, + minWidth: 100, + align: 'center', + headerAlign: 'center', + headerClassName: `${styles.tableHeader}`, + sortable: false, + renderCell: (params: GridCellParams) => { + return
    {params.row.id}
    ; + }, + }, + { + field: 'fundName', + headerName: 'Fund Name', + flex: 2, + align: 'center', + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + return ( +
    handleClick(params.row._id as string)} + > + {params.row.name} +
    + ); + }, + }, + { + field: 'createdBy', + headerName: 'Created By', + flex: 2, + align: 'center', + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + return params.row.creator.firstName + ' ' + params.row.creator.lastName; + }, + }, + { + field: 'createdOn', + headerName: 'Created On', + align: 'center', + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + flex: 2, + renderCell: (params: GridCellParams) => { + return ( +
    + {dayjs(params.row.createdAt).format('DD/MM/YYYY')} +
    + ); + }, + }, + { + field: 'status', + headerName: 'Status', + flex: 2, + align: 'center', + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + return params.row.isArchived ? 'Archived' : 'Active'; + }, + }, + { + field: 'action', + headerName: 'Action', + flex: 2, + align: 'center', + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + return ( + <> + + + ); + }, + }, + { + field: 'assocCampaigns', + headerName: 'Associated Campaigns', + flex: 2, + align: 'center', + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + return ( + + ); + }, + }, + ]; + return ( - <> - -
    -
    -
    - ) => { - setFullName(e.target.value); - }} - data-testid="searchFullName" - /> - +
    +
    +
    + + - - -
    -
    -
    - - - - {tCommon('filter')} - - -
    -
    - -
    -
    + {t('createdEarliest')} + + + +
    +
    +
    - -
    -
    - {fundData?.fundsByOrganization && - fundData.fundsByOrganization.length > 0 ? ( -
    - - - - - # - - {t('fundName')} - - - {t('createdBy')} - - - {t('createdOn')} - - - {t('status')} - - - {t('manageFund')} - - - - - {fundData.fundsByOrganization.map( - (fund: any, index: number) => ( - - - {index + 1} - - handleClick(fund._id)} - > - - {fund.name} - - - - {fund.creator.firstName} {fund.creator.lastName} - - - {dayjs(fund.createdAt).format('DD/MM/YYYY')} - - - - - - - - - ), - )} - -
    -
    -
    - ) : ( -
    -
    {t('noFundsFound')}
    -
    - )} -
    - {/* - - {/*
    - + + row._id} + slots={{ + noRowsOverlay: () => ( + + {t('noFundsFound')} + + ), + }} + sx={dataGridStyle} + getRowClassName={() => `${styles.rowBackground}`} + autoHeight + rowHeight={65} + rows={funds.map((fund, index) => ({ + id: index + 1, + ...fund, + }))} + columns={columns} + isRowSelectable={() => false} + /> + setModalState(false)} + refetchFunds={refetchFunds} + fund={fund} + orgId={orgId} + mode={fundModalMode} + /> +
    ); }; diff --git a/src/screens/OrganizationFunds/OrganizationFundsMocks.ts b/src/screens/OrganizationFunds/OrganizationFundsMocks.ts index cb1e07d78f..81e5a0fb64 100644 --- a/src/screens/OrganizationFunds/OrganizationFundsMocks.ts +++ b/src/screens/OrganizationFunds/OrganizationFundsMocks.ts @@ -1,6 +1,5 @@ import { CREATE_FUND_MUTATION, - REMOVE_FUND_MUTATION, UPDATE_FUND_MUTATION, } from 'GraphQl/Mutations/FundMutation'; import { FUND_LIST } from 'GraphQl/Queries/fundQueries'; @@ -10,21 +9,23 @@ export const MOCKS = [ request: { query: FUND_LIST, variables: { - id: undefined, + organizationId: 'orgId', + orderBy: 'createdAt_DESC', + filter: '', }, }, result: { data: { fundsByOrganization: [ { - _id: '1', + _id: 'fundId', name: 'Fund 1', - refrenceNumber: '123', + refrenceNumber: '1111', taxDeductible: true, isArchived: false, isDefault: false, - createdAt: '2021-07-01T00:00:00.000Z', - organizationId: 'organizationId1', + createdAt: '2024-06-22', + organizationId: 'orgId', creator: { _id: 'creatorId1', firstName: 'John', @@ -32,14 +33,14 @@ export const MOCKS = [ }, }, { - _id: '99', - name: 'Funndds', - refrenceNumber: '1234', + _id: 'fundId2', + name: 'Fund 2', + refrenceNumber: '2222', taxDeductible: true, isArchived: true, isDefault: false, - createdAt: '2021-07-01T00:00:00.000Z', - organizationId: 'organizationId1', + createdAt: '2024-06-21', + organizationId: 'orgId', creator: { _id: 'creatorId1', firstName: 'John', @@ -50,108 +51,27 @@ export const MOCKS = [ }, }, }, - { - request: { - query: CREATE_FUND_MUTATION, - variables: { - name: 'Test Fund', - refrenceNumber: '1', - taxDeductible: true, - isArchived: false, - isDefault: false, - organizationId: undefined, - }, - }, - result: { - data: { - createFund: { - _id: '3', - }, - }, - }, - }, - { - request: { - query: UPDATE_FUND_MUTATION, - variables: { - id: '1', - name: 'Test Fund', - refrenceNumber: '1', - taxDeductible: false, - isArchived: true, - isDefault: true, - }, - }, - result: { - data: { - updateFund: { - _id: '1', - }, - }, - }, - }, - { - request: { - query: REMOVE_FUND_MUTATION, - variables: { - id: '1', - }, - }, - result: { - data: { - removeFund: { - _id: '1', - }, - }, - }, - }, -]; -export const NO_FUNDS = [ - { - request: { - query: FUND_LIST, - variables: { - id: undefined, - }, - }, - result: { - data: { - fundsByOrganization: [], - }, - }, - }, -]; -export const MOCKS_ERROR_ORGANIZATIONS_FUNDS = [ - { - request: { - query: FUND_LIST, - variables: { - organizationId: '1', - }, - }, - error: new Error('Mock graphql error'), - }, -]; -export const MOCKS_ERROR_CREATE_FUND = [ { request: { query: FUND_LIST, variables: { - id: undefined, + organizationId: 'orgId', + orderBy: 'createdAt_ASC', + filter: '', }, }, result: { data: { fundsByOrganization: [ { - _id: '1', - name: 'Fund 1', - refrenceNumber: '123', + _id: 'fundId', + name: 'Fund 2', + refrenceNumber: '2222', taxDeductible: true, - isArchived: false, + isArchived: true, isDefault: false, - createdAt: '2021-07-01T00:00:00.000Z', - organizationId: 'organizationId1', + createdAt: '2024-06-21', + organizationId: 'orgId', creator: { _id: 'creatorId1', firstName: 'John', @@ -159,17 +79,17 @@ export const MOCKS_ERROR_CREATE_FUND = [ }, }, { - _id: '2', - name: 'Fund 2', - refrenceNumber: '456', - taxDeductible: false, + _id: 'fundId2', + name: 'Fund 1', + refrenceNumber: '1111', + taxDeductible: true, isArchived: false, isDefault: false, - createdAt: '2021-07-01T00:00:00.000Z', - organizationId: 'organizationId2', + createdAt: '2024-06-22', + organizationId: 'orgId', creator: { - _id: 'creatorId2', - firstName: 'Jane', + _id: 'creatorId1', + firstName: 'John', lastName: 'Doe', }, }, @@ -177,62 +97,33 @@ export const MOCKS_ERROR_CREATE_FUND = [ }, }, }, - { - request: { - query: CREATE_FUND_MUTATION, - variables: { - name: 'Fund 3', - refrenceNumber: '789', - taxDeductible: true, - isArchived: false, - isDefault: false, - organizationId: undefined, - }, - }, - error: new Error('Mock graphql error'), - }, -]; -export const MOCKS_ERROR_UPDATE_FUND = [ { request: { query: FUND_LIST, variables: { - id: undefined, + organizationId: 'orgId', + orderBy: 'createdAt_DESC', + filter: '2', }, }, result: { data: { fundsByOrganization: [ { - _id: '1', - name: 'Fund 1', - refrenceNumber: '123', + _id: 'fundId', + name: 'Fund 2', + refrenceNumber: '2222', taxDeductible: true, - isArchived: false, + isArchived: true, isDefault: false, - createdAt: '2021-07-01T00:00:00.000Z', - organizationId: 'organizationId1', + createdAt: '2024-06-21', + organizationId: 'orgId', creator: { _id: 'creatorId1', firstName: 'John', lastName: 'Doe', }, }, - { - _id: '2', - name: 'Fund 2', - refrenceNumber: '456', - taxDeductible: false, - isArchived: false, - isDefault: false, - createdAt: '2021-07-01T00:00:00.000Z', - organizationId: 'organizationId2', - creator: { - _id: 'creatorId2', - firstName: 'Jane', - lastName: 'Doe', - }, - }, ], }, }, @@ -241,18 +132,18 @@ export const MOCKS_ERROR_UPDATE_FUND = [ request: { query: CREATE_FUND_MUTATION, variables: { - name: 'Fund 3', - refrenceNumber: '789', - taxDeductible: true, + name: 'Fund 2', + refrenceNumber: '2222', + taxDeductible: false, isArchived: false, - isDefault: false, - organizationId: undefined, + isDefault: true, + organizationId: 'orgId', }, }, result: { data: { createFund: { - _id: '3', + _id: '2222', }, }, }, @@ -261,106 +152,78 @@ export const MOCKS_ERROR_UPDATE_FUND = [ request: { query: UPDATE_FUND_MUTATION, variables: { - id: undefined, - name: 'Fund 1', - refrenceNumber: '789', - taxDeductible: true, - isArchived: false, - isDefault: false, + id: 'fundId', + name: 'Fund 2', + refrenceNumber: '2222', + taxDeductible: false, + isArchived: true, + isDefault: true, + }, + }, + result: { + data: { + updateFund: { + _id: 'fundId', + }, }, }, - error: new Error('Mock graphql error'), }, ]; -export const MOCKS_ERROR_REMOVE_FUND = [ + +export const NO_FUNDS = [ { request: { query: FUND_LIST, variables: { - id: undefined, + organizationId: 'orgId', + orderBy: 'createdAt_DESC', + filter: '', }, }, result: { data: { - fundsByOrganization: [ - { - _id: '3', - name: 'Fund 1', - refrenceNumber: '123', - taxDeductible: true, - isArchived: false, - isDefault: false, - createdAt: '2021-07-01T00:00:00.000Z', - organizationId: 'organizationId1', - creator: { - _id: 'creatorId1', - firstName: 'John', - lastName: 'Doe', - }, - }, - { - _id: '2', - name: 'Fund 2', - refrenceNumber: '456', - taxDeductible: false, - isArchived: false, - isDefault: false, - createdAt: '2021-07-01T00:00:00.000Z', - organizationId: 'organizationId2', - creator: { - _id: 'creatorId2', - firstName: 'Jane', - lastName: 'Doe', - }, - }, - ], + fundsByOrganization: [], }, }, }, +]; + +export const MOCKS_ERROR = [ { request: { - query: CREATE_FUND_MUTATION, + query: FUND_LIST, variables: { - name: 'Fund 3', - refrenceNumber: '789', - taxDeductible: true, - isArchived: false, - isDefault: false, - organizationId: undefined, - }, - }, - result: { - data: { - createFund: { - _id: '3', - }, + organizationId: 'orgId', + orderBy: 'createdAt_DESC', + filter: '', }, }, + error: new Error('Mock graphql error'), }, { request: { - query: UPDATE_FUND_MUTATION, + query: CREATE_FUND_MUTATION, variables: { - id: undefined, - name: 'Fund 1', - taxDeductible: true, + name: 'Fund 2', + refrenceNumber: '2222', + taxDeductible: false, isArchived: false, - isDefault: false, - }, - }, - result: { - data: { - updateFund: { - _id: '1', - }, + isDefault: true, + organizationId: 'orgId', }, }, + error: new Error('Mock graphql error'), }, { request: { - query: REMOVE_FUND_MUTATION, + query: UPDATE_FUND_MUTATION, variables: { - id: undefined, + id: 'fundId', + name: 'Fund 2', + refrenceNumber: '2222', + taxDeductible: false, + isArchived: true, + isDefault: true, }, }, error: new Error('Mock graphql error'), diff --git a/src/screens/OrganizationPeople/AddMember.tsx b/src/screens/OrganizationPeople/AddMember.tsx index 696436c2bc..4c1f15106e 100644 --- a/src/screens/OrganizationPeople/AddMember.tsx +++ b/src/screens/OrganizationPeople/AddMember.tsx @@ -31,6 +31,7 @@ import type { InterfaceQueryUserListItem, } from 'utils/interfaces'; import styles from './OrganizationPeople.module.css'; +import Avatar from 'components/Avatar/Avatar'; const StyledTableCell = styled(TableCell)(({ theme }) => ({ [`&.${tableCellClasses.head}`]: { @@ -48,6 +49,15 @@ const StyledTableRow = styled(TableRow)(() => ({ }, })); +/** + * AddMember component is used to add new members to the organization by selecting from + * the existing users or creating a new user. + * It uses the following queries and mutations: + * ORGANIZATIONS_LIST, + * ORGANIZATIONS_MEMBER_CONNECTION_LIST, + * USERS_CONNECTION_LIST, + * ADD_MEMBER_MUTATION,SIGNUP_MUTATION. + */ function AddMember(): JSX.Element { const { t: translateOrgPeople } = useTranslation('translation', { keyPrefix: 'organizationPeople', @@ -57,6 +67,8 @@ function AddMember(): JSX.Element { keyPrefix: 'addMember', }); + const { t: tCommon } = useTranslation('common'); + document.title = translateOrgPeople('title'); const [addUserModalisOpen, setAddUserModalIsOpen] = useState(false); @@ -90,7 +102,7 @@ function AddMember(): JSX.Element { orgid: currentUrl, }, }); - toast.success('Member added to the organization.'); + toast.success(tCommon('addedSuccessfully', { item: 'Member' }) as string); memberRefetch({ orgId: currentUrl, }); @@ -182,11 +194,11 @@ function AddMember(): JSX.Element { createUserVariables.lastName ) ) { - toast.error(translateOrgPeople('invalidDetailsMessage')); + toast.error(translateOrgPeople('invalidDetailsMessage') as string); } else if ( createUserVariables.password !== createUserVariables.confirmPassword ) { - toast.error(translateOrgPeople('passwordNotMatch')); + toast.error(translateOrgPeople('passwordNotMatch') as string); } else { try { const registeredUser = await registerMutation({ @@ -285,8 +297,8 @@ function AddMember(): JSX.Element { { openAddUserModal(); @@ -298,8 +310,8 @@ function AddMember(): JSX.Element { { openCreateNewUserModal(); @@ -355,6 +367,9 @@ function AddMember(): JSX.Element { # + + {translateAddMember('profile')} + {translateAddMember('user')} @@ -378,11 +393,29 @@ function AddMember(): JSX.Element { {index + 1} + + {userDetails.user.image ? ( + avatar + ) : ( + + )} + {userDetails.user.firstName + diff --git a/src/screens/OrganizationPeople/OrganizationPeople.test.tsx b/src/screens/OrganizationPeople/OrganizationPeople.test.tsx index 8ea7b30219..a840f1e1f0 100644 --- a/src/screens/OrganizationPeople/OrganizationPeople.test.tsx +++ b/src/screens/OrganizationPeople/OrganizationPeople.test.tsx @@ -1,6 +1,6 @@ -import React from 'react'; +import React, { act } from 'react'; import { MockedProvider } from '@apollo/react-testing'; -import { act, fireEvent, render, screen } from '@testing-library/react'; +import { fireEvent, render, screen } from '@testing-library/react'; import { Provider } from 'react-redux'; import { BrowserRouter } from 'react-router-dom'; import userEvent from '@testing-library/user-event'; @@ -423,6 +423,32 @@ const MOCKS: TestMock[] = [ user: { firstName: 'Vyvyan', lastName: 'Kerry', + image: 'tempUrl', + _id: '65378abd85008f171cf2990d', + email: 'testadmin1@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + joinedOrganizations: [ + { + _id: '6537904485008f171cf29924', + name: 'Unity Foundation', + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + }, + __typename: 'Organization', + }, + ], + __typename: 'User', + }, + }, + { + user: { + firstName: 'Nandika', + lastName: 'Agrawal', image: null, _id: '65378abd85008f171cf2990d', email: 'testadmin1@example.com', @@ -916,10 +942,13 @@ describe('Organization People Page', () => { userEvent.click(screen.getByTestId('existingUser')); await wait(); - expect(screen.getByTestId('addExistingUserModal')).toBeInTheDocument(); + expect( + screen.getAllByTestId('addExistingUserModal').length, + ).toBeGreaterThan(0); await wait(); - userEvent.click(screen.getByTestId('addBtn')); + const addBtn = screen.getAllByTestId('addBtn'); + userEvent.click(addBtn[0]); }); test('Open and search existing user', async () => { @@ -1353,3 +1382,54 @@ describe('Organization People Page', () => { expect(screen.queryByText(/Nothing Found !!/i)).toBeInTheDocument(); }); }); + +test('Open and check if profile image is displayed for existing user', async () => { + window.location.assign('/orgpeople/orgid'); + render( + + + + + + + + + , + ); + + // Wait for the component to finish rendering + await wait(); + + // Click on the dropdown toggle to open the menu + userEvent.click(screen.getByTestId('addMembers')); + await wait(); + + // Click on the "Admins" option in the dropdown menu + userEvent.click(screen.getByTestId('existingUser')); + await wait(); + + expect(screen.getByTestId('addExistingUserModal')).toBeInTheDocument(); + await wait(); + + expect(screen.getAllByTestId('user').length).toBeGreaterThan(0); + await wait(); + + // Check if the image is rendered + expect(screen.getAllByTestId('profileImage').length).toBeGreaterThan(0); + await wait(); + + const images = await screen.findAllByAltText('avatar'); + expect(images.length).toBeGreaterThan(0); + await wait(); + + const avatarImages = await screen.findAllByAltText('Dummy Avatar'); + expect(avatarImages.length).toBeGreaterThan(0); + await wait(); +}); diff --git a/src/screens/OrganizationPeople/OrganizationPeople.tsx b/src/screens/OrganizationPeople/OrganizationPeople.tsx index 6a2626fd95..1d230ed058 100644 --- a/src/screens/OrganizationPeople/OrganizationPeople.tsx +++ b/src/screens/OrganizationPeople/OrganizationPeople.tsx @@ -22,6 +22,12 @@ import type { GridColDef, GridCellParams } from '@mui/x-data-grid'; import { Stack } from '@mui/material'; import Avatar from 'components/Avatar/Avatar'; +/** + * OrganizationPeople component is used to display the list of members, admins and users of the organization. + * It also provides the functionality to search the members, admins and users by their full name. + * It also provides the functionality to remove the members and admins from the organization. + * @returns JSX.Element which contains the list of members, admins and users of the organization. + */ function organizationPeople(): JSX.Element { const { t } = useTranslation('translation', { keyPrefix: 'organizationPeople', @@ -307,10 +313,10 @@ function organizationPeople(): JSX.Element { { @@ -322,10 +328,10 @@ function organizationPeople(): JSX.Element { { @@ -335,10 +341,10 @@ function organizationPeople(): JSX.Element { { @@ -362,12 +368,12 @@ function organizationPeople(): JSX.Element {
    row._id} - components={{ - NoRowsOverlay: () => ( + slots={{ + noRowsOverlay: () => ( { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + error: jest.fn(), + }, +})); + +const renderOrganizationTags = (link: ApolloLink): RenderResult => { + return render( + + + + + + } /> +
    } + /> +
    } + /> + + + + + , + ); +}; + +describe('Organisation Tags Page', () => { + beforeEach(() => { + jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: 'orgId' }), + })); + }); + + afterEach(() => { + jest.clearAllMocks(); + cleanup(); + }); + + test('Component loads correctly', async () => { + const { getByText } = renderOrganizationTags(link); + + await wait(); + + await waitFor(() => { + expect(getByText(translations.createTag)).toBeInTheDocument(); + }); + }); + + test('render error component on unsuccessful userTags query', async () => { + const { queryByText } = renderOrganizationTags(link2); + + await wait(); + + await waitFor(() => { + expect(queryByText(translations.create)).not.toBeInTheDocument(); + }); + }); + + test('opens and closes the create tag modal', async () => { + renderOrganizationTags(link); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('createTagBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('createTagBtn')); + + await waitFor(() => { + return expect( + screen.findByTestId('closeCreateTagModal'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('closeCreateTagModal')); + + await waitForElementToBeRemoved(() => + screen.queryByTestId('closeCreateTagModal'), + ); + }); + + test('opens and closes the remove tag modal', async () => { + renderOrganizationTags(link); + + await wait(); + + await waitFor(() => { + expect(screen.getAllByTestId('removeUserTagBtn')[0]).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('removeUserTagBtn')[0]); + + await waitFor(() => { + return expect( + screen.findByTestId('removeUserTagModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('removeUserTagModalCloseBtn')); + + await waitForElementToBeRemoved(() => + screen.queryByTestId('removeUserTagModalCloseBtn'), + ); + }); + + test('navigates to sub tags screen after clicking on a tag', async () => { + renderOrganizationTags(link); + + await wait(); + + await waitFor(() => { + expect(screen.getAllByTestId('tagName')[0]).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('tagName')[0]); + + await waitFor(() => { + expect(screen.getByTestId('subTagsScreen')).toBeInTheDocument(); + }); + }); + + test('navigates to manage tag page after clicking manage tag option', async () => { + renderOrganizationTags(link); + + await wait(); + + await waitFor(() => { + expect(screen.getAllByTestId('manageTagBtn')[0]).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('manageTagBtn')[0]); + + await waitFor(() => { + expect(screen.getByTestId('manageTagScreen')).toBeInTheDocument(); + }); + }); + + test('paginates between different pages', async () => { + renderOrganizationTags(link); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('nextPagBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('nextPagBtn')); + + await waitFor(() => { + expect(screen.getAllByTestId('tagName')[0]).toHaveTextContent('6'); + }); + + await waitFor(() => { + expect(screen.getByTestId('previousPageBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('previousPageBtn')); + + await waitFor(() => { + expect(screen.getAllByTestId('tagName')[0]).toHaveTextContent('1'); + }); + }); + + test('creates a new user tag', async () => { + renderOrganizationTags(link); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('createTagBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('createTagBtn')); + + userEvent.type( + screen.getByPlaceholderText(translations.tagNamePlaceholder), + '7', + ); + + userEvent.click(screen.getByTestId('createTagSubmitBtn')); + + await waitFor(() => { + expect(toast.success).toBeCalledWith(translations.tagCreationSuccess); + }); + }); + + test('removes a user tag', async () => { + renderOrganizationTags(link); + + await wait(); + + await waitFor(() => { + expect(screen.getAllByTestId('removeUserTagBtn')[0]).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('removeUserTagBtn')[0]); + + userEvent.click(screen.getByTestId('removeUserTagSubmitBtn')); + + await waitFor(() => { + expect(toast.success).toBeCalledWith(translations.tagRemovalSuccess); + }); + }); +}); diff --git a/src/screens/OrganizationTags/OrganizationTags.tsx b/src/screens/OrganizationTags/OrganizationTags.tsx new file mode 100644 index 0000000000..e4bf0604e9 --- /dev/null +++ b/src/screens/OrganizationTags/OrganizationTags.tsx @@ -0,0 +1,515 @@ +import { useMutation, useQuery, type ApolloError } from '@apollo/client'; +import { Search, WarningAmberRounded } from '@mui/icons-material'; +import SortIcon from '@mui/icons-material/Sort'; +import Loader from 'components/Loader/Loader'; +import IconComponent from 'components/IconComponent/IconComponent'; +import { useNavigate, useParams, Link } from 'react-router-dom'; +import type { ChangeEvent } from 'react'; +import React, { useState } from 'react'; +import { Form } from 'react-bootstrap'; +import Button from 'react-bootstrap/Button'; +import Dropdown from 'react-bootstrap/Dropdown'; +import Modal from 'react-bootstrap/Modal'; +import Row from 'react-bootstrap/Row'; +import { useTranslation } from 'react-i18next'; +import { toast } from 'react-toastify'; +import type { InterfaceQueryOrganizationUserTags } from 'utils/interfaces'; +import styles from './OrganizationTags.module.css'; +import { DataGrid } from '@mui/x-data-grid'; +import { dataGridStyle } from 'utils/organizationTagsUtils'; +import type { GridCellParams, GridColDef } from '@mui/x-data-grid'; +import { Stack } from '@mui/material'; +import { ORGANIZATION_USER_TAGS_LIST } from 'GraphQl/Queries/OrganizationQueries'; +import { + CREATE_USER_TAG, + REMOVE_USER_TAG, +} from 'GraphQl/Mutations/TagMutations'; + +/** + * Component that renders the Organization Tags screen when the app navigates to '/orgtags/:orgId'. + * + * This component does not accept any props and is responsible for displaying + * the content associated with the corresponding route. + */ + +function OrganizationTags(): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'organizationTags', + }); + const { t: tCommon } = useTranslation('common'); + + const [createTagModalIsOpen, setCreateTagModalIsOpen] = useState(false); + + const { orgId } = useParams(); + const navigate = useNavigate(); + const [after, setAfter] = useState(null); + const [before, setBefore] = useState(null); + const [first, setFirst] = useState(5); + const [last, setLast] = useState(null); + const [tagSerialNumber, setTagSerialNumber] = useState(0); + + const [tagName, setTagName] = useState(''); + + const [removeUserTagId, setRemoveUserTagId] = useState(null); + const [removeTagModalIsOpen, setRemoveTagModalIsOpen] = useState(false); + + const showCreateTagModal = (): void => { + setTagName(''); + setCreateTagModalIsOpen(true); + }; + + const hideCreateTagModal = (): void => { + setCreateTagModalIsOpen(false); + }; + + const { + data: orgUserTagsData, + loading: orgUserTagsLoading, + error: orgUserTagsError, + refetch: orgUserTagsRefetch, + }: { + data?: { + organizations: InterfaceQueryOrganizationUserTags[]; + }; + loading: boolean; + error?: ApolloError; + refetch: () => void; + } = useQuery(ORGANIZATION_USER_TAGS_LIST, { + variables: { + id: orgId, + after: after, + before: before, + first: first, + last: last, + }, + }); + + const [create, { loading: createUserTagLoading }] = + useMutation(CREATE_USER_TAG); + + const createTag = async (e: ChangeEvent): Promise => { + e.preventDefault(); + + try { + const { data } = await create({ + variables: { + name: tagName, + organizationId: orgId, + }, + }); + + if (data) { + toast.success(t('tagCreationSuccess') as string); + orgUserTagsRefetch(); + setTagName(''); + setCreateTagModalIsOpen(false); + } + } catch (error: unknown) { + /* istanbul ignore next */ + if (error instanceof Error) { + toast.error(error.message); + } + } + }; + + const [removeUserTag] = useMutation(REMOVE_USER_TAG); + const handleRemoveUserTag = async (): Promise => { + try { + await removeUserTag({ + variables: { + id: removeUserTagId, + }, + }); + + orgUserTagsRefetch(); + toggleRemoveUserTagModal(); + toast.success(t('tagRemovalSuccess') as string); + } catch (error: unknown) { + /* istanbul ignore next */ + if (error instanceof Error) { + toast.error(error.message); + } + } + }; + + if (createUserTagLoading || orgUserTagsLoading) { + return ; + } + + if (orgUserTagsError) { + return ( +
    +
    + +
    + Error occured while loading Organization Tags Data +
    + {orgUserTagsError.message} +
    +
    +
    + ); + } + + const handleNextPage = (): void => { + setAfter(orgUserTagsData?.organizations[0].userTags.pageInfo.endCursor); + setBefore(null); + setFirst(5); + setLast(null); + setTagSerialNumber(tagSerialNumber + 1); + }; + const handlePreviousPage = (): void => { + setBefore(orgUserTagsData?.organizations[0].userTags.pageInfo.startCursor); + setAfter(null); + setFirst(null); + setLast(5); + setTagSerialNumber(tagSerialNumber - 1); + }; + + const userTagsList = orgUserTagsData?.organizations[0].userTags.edges.map( + (edge) => edge.node, + ); + + const redirectToManageTag = (tagId: string): void => { + navigate(`/orgtags/${orgId}/managetag/${tagId}`); + }; + + const redirectToSubTags = (tagId: string): void => { + navigate(`/orgtags/${orgId}/subTags/${tagId}`); + }; + + const toggleRemoveUserTagModal = (): void => { + if (removeTagModalIsOpen) setRemoveUserTagId(null); + setRemoveTagModalIsOpen(!removeTagModalIsOpen); + }; + + const columns: GridColDef[] = [ + { + field: 'id', + headerName: '#', + minWidth: 100, + align: 'center', + headerAlign: 'center', + headerClassName: `${styles.tableHeader}`, + sortable: false, + renderCell: (params: GridCellParams) => { + return
    {tagSerialNumber * 5 + params.row.id}
    ; + }, + }, + { + field: 'tagName', + headerName: 'Tag Name', + flex: 1, + minWidth: 100, + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + return ( +
    redirectToSubTags(params.row._id)} + > + {params.row.name} + + +
    + ); + }, + }, + { + field: 'totalSubTags', + headerName: 'Total Sub Tags', + flex: 1, + align: 'center', + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + return ( + + {params.row.childTags.totalCount} + + ); + }, + }, + { + field: 'totalAssignedUsers', + headerName: 'Total Assigned Users', + flex: 1, + align: 'center', + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + return ( + + {params.row.usersAssignedTo.totalCount} + + ); + }, + }, + { + field: 'actions', + headerName: 'Actions', + flex: 1, + align: 'center', + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + return ( +
    + + + +
    + ); + }, + }, + ]; + + return ( + <> + +
    +
    +
    + + +
    +
    + +
    + +
    + +
    +
    +
    + +
    + +
    + {'Tags'} +
    +
    + row._id} + slots={{ + noRowsOverlay: /* istanbul ignore next */ () => ( + + {t('noTagsFound')} + + ), + }} + sx={dataGridStyle} + getRowClassName={() => `${styles.rowBackground}`} + autoHeight + rowHeight={65} + rows={userTagsList?.map((fund, index) => ({ + id: index + 1, + ...fund, + }))} + columns={columns} + isRowSelectable={() => false} + /> +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    + + {/* Create Tag Modal */} + + + {t('tagDetails')} + +
    + + {t('tagName')} + { + setTagName(e.target.value); + }} + /> + + + + + + +
    +
    + + {/* Remove User Tag Modal */} + + + + {t('removeUserTag')} + + + {t('removeUserTagMessage')} + + + + + + + ); +} + +export default OrganizationTags; diff --git a/src/screens/OrganizationTags/OrganizationTagsMocks.ts b/src/screens/OrganizationTags/OrganizationTagsMocks.ts new file mode 100644 index 0000000000..3700c66c46 --- /dev/null +++ b/src/screens/OrganizationTags/OrganizationTagsMocks.ts @@ -0,0 +1,291 @@ +import { + CREATE_USER_TAG, + REMOVE_USER_TAG, +} from 'GraphQl/Mutations/TagMutations'; +import { ORGANIZATION_USER_TAGS_LIST } from 'GraphQl/Queries/OrganizationQueries'; + +export const MOCKS = [ + { + request: { + query: ORGANIZATION_USER_TAGS_LIST, + variables: { + id: '123', + after: null, + before: null, + first: 5, + last: null, + }, + }, + result: { + data: { + organizations: [ + { + userTags: { + edges: [ + { + node: { + _id: '1', + name: 'userTag 1', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 5, + }, + }, + cursor: '1', + }, + { + node: { + _id: '2', + name: 'userTag 2', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 0, + }, + }, + cursor: '2', + }, + { + node: { + _id: '3', + name: 'userTag 3', + usersAssignedTo: { + totalCount: 0, + }, + childTags: { + totalCount: 5, + }, + }, + cursor: '3', + }, + { + node: { + _id: '4', + name: 'userTag 4', + usersAssignedTo: { + totalCount: 0, + }, + childTags: { + totalCount: 0, + }, + }, + cursor: '4', + }, + { + node: { + _id: '5', + name: 'userTag 5', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 5, + }, + }, + cursor: '5', + }, + ], + pageInfo: { + startCursor: '1', + endCursor: '5', + hasNextPage: true, + hasPreviousPage: false, + }, + totalCount: 6, + }, + }, + ], + }, + }, + }, + { + request: { + query: ORGANIZATION_USER_TAGS_LIST, + variables: { + id: '123', + after: '5', + before: null, + first: 5, + last: null, + }, + }, + result: { + data: { + organizations: [ + { + userTags: { + edges: [ + { + node: { + _id: '6', + name: 'userTag 6', + usersAssignedTo: { + totalCount: 0, + }, + childTags: { + totalCount: 0, + }, + }, + cursor: '6', + }, + ], + pageInfo: { + startCursor: '6', + endCursor: '6', + hasNextPage: false, + hasPreviousPage: true, + }, + totalCount: 6, + }, + }, + ], + }, + }, + }, + { + request: { + query: ORGANIZATION_USER_TAGS_LIST, + variables: { + id: '123', + after: null, + before: '6', + first: null, + last: 5, + }, + }, + result: { + data: { + organizations: [ + { + userTags: { + edges: [ + { + node: { + _id: '1', + name: 'userTag 1', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 5, + }, + }, + cursor: '1', + }, + { + node: { + _id: '2', + name: 'userTag 2', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 0, + }, + }, + cursor: '2', + }, + { + node: { + _id: '3', + name: 'userTag 3', + usersAssignedTo: { + totalCount: 0, + }, + childTags: { + totalCount: 5, + }, + }, + cursor: '3', + }, + { + node: { + _id: '4', + name: 'userTag 4', + usersAssignedTo: { + totalCount: 0, + }, + childTags: { + totalCount: 0, + }, + }, + cursor: '4', + }, + { + node: { + _id: '5', + name: 'userTag 5', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 5, + }, + }, + cursor: '5', + }, + ], + pageInfo: { + startCursor: '1', + endCursor: '5', + hasNextPage: true, + hasPreviousPage: false, + }, + totalCount: 6, + }, + }, + ], + }, + }, + }, + { + request: { + query: CREATE_USER_TAG, + variables: { + name: '7', + organizationId: '123', + }, + }, + result: { + data: { + createUserTag: { + _id: '7', + }, + }, + }, + }, + { + request: { + query: REMOVE_USER_TAG, + variables: { + id: '1', + }, + }, + result: { + data: { + removeUserTag: { + _id: '1', + }, + }, + }, + }, +]; + +export const MOCKS_ERROR = [ + { + request: { + query: ORGANIZATION_USER_TAGS_LIST, + variables: { + id: '123', + after: null, + before: null, + first: 5, + last: null, + }, + }, + error: new Error('Mock Graphql Error'), + }, +]; diff --git a/src/screens/OrganizationVenues/OrganizationVenues.tsx b/src/screens/OrganizationVenues/OrganizationVenues.tsx index 6c08733e17..c2c3afe7e4 100644 --- a/src/screens/OrganizationVenues/OrganizationVenues.tsx +++ b/src/screens/OrganizationVenues/OrganizationVenues.tsx @@ -15,13 +15,21 @@ import { DELETE_VENUE_MUTATION } from 'GraphQl/Mutations/VenueMutations'; import type { InterfaceQueryVenueListItem } from 'utils/interfaces'; import VenueCard from 'components/Venues/VenueCard'; +/** + * Component to manage and display the list of organization venues. + * Handles searching, sorting, and CRUD operations for venues. + */ function organizationVenues(): JSX.Element { + // Translation hooks for i18n support const { t } = useTranslation('translation', { keyPrefix: 'organizationVenues', }); const { t: tCommon } = useTranslation('common'); + // Setting the document title using the translation hook document.title = t('title'); + + // State hooks for managing component state const [venueModal, setVenueModal] = useState(false); const [venueModalMode, setVenueModalMode] = useState<'edit' | 'create'>( 'create', @@ -33,11 +41,13 @@ function organizationVenues(): JSX.Element { useState(null); const [venues, setVenues] = useState([]); + // Getting the organization ID from the URL parameters const { orgId } = useParams(); if (!orgId) { return ; } + // GraphQL query for fetching venue data const { data: venueData, loading: venueLoading, @@ -54,8 +64,13 @@ function organizationVenues(): JSX.Element { }, }); + // GraphQL mutation for deleting a venue const [deleteVenue] = useMutation(DELETE_VENUE_MUTATION); + /** + * Handles the deletion of a venue by ID. + * @param venueId - The ID of the venue to delete. + */ const handleDelete = async (venueId: string): Promise => { try { await deleteVenue({ @@ -68,36 +83,57 @@ function organizationVenues(): JSX.Element { } }; + /** + * Updates the search term state when the user types in the search input. + * @param event - The input change event. + */ const handleSearchChange = ( event: React.ChangeEvent, ): void => { setSearchTerm(event.target.value); }; + /** + * Updates the sort order state when the user selects a sort option. + * @param order - The order to sort venues by (highest or lowest capacity). + */ const handleSortChange = (order: 'highest' | 'lowest'): void => { setSortOrder(order); }; + /** + * Toggles the visibility of the venue modal. + */ const toggleVenueModal = (): void => { setVenueModal(!venueModal); }; + /** + * Shows the edit venue modal with the selected venue data. + * @param venueItem - The venue data to edit. + */ const showEditVenueModal = (venueItem: InterfaceQueryVenueListItem): void => { setVenueModalMode('edit'); setEditVenueData(venueItem); toggleVenueModal(); }; + /** + * Shows the create venue modal. + */ const showCreateVenueModal = (): void => { setVenueModalMode('create'); setEditVenueData(null); toggleVenueModal(); }; + + // Error handling for venue data fetch /* istanbul ignore next */ if (venueError) { errorHandler(t, venueError); } + // Updating venues state when venue data changes useEffect(() => { if (venueData && venueData.getVenueByOrgId) { setVenues(venueData.getVenueByOrgId); diff --git a/src/screens/PageNotFound/PageNotFound.tsx b/src/screens/PageNotFound/PageNotFound.tsx index 92f4a98f7e..037aeecbab 100644 --- a/src/screens/PageNotFound/PageNotFound.tsx +++ b/src/screens/PageNotFound/PageNotFound.tsx @@ -4,17 +4,26 @@ import { useTranslation } from 'react-i18next'; import useLocalStorage from 'utils/useLocalstorage'; import styles from './PageNotFound.module.css'; -import Logo from 'assets/images/talawa-logo-200x200.png'; +import Logo from 'assets/images/talawa-logo-600x600.png'; +/** + * The `PageNotFound` component displays a 404 error page when a user navigates to a non-existent route. + * It shows a message indicating that the page was not found and provides a link to redirect users back + * to the appropriate home page based on their admin status. + * + */ const PageNotFound = (): JSX.Element => { + // Translation hooks for internationalization const { t } = useTranslation('translation', { keyPrefix: 'pageNotFound', }); const { t: tCommon } = useTranslation('common'); const { t: tErrors } = useTranslation('errors'); + // Set the document title to the translated title for the 404 page document.title = t('title'); + // Get the admin status from local storage const { getItem } = useLocalStorage(); const adminFor = getItem('AdminFor'); @@ -23,6 +32,7 @@ const PageNotFound = (): JSX.Element => {
    Logo + {/* Display a message based on admin status */} {adminFor != undefined ? (

    {tCommon('talawaAdminPortal')} @@ -31,10 +41,13 @@ const PageNotFound = (): JSX.Element => {

    {t('talawaUser')}

    )}
    + {/* Display the 404 error code */}

    {t('404')}

    + {/* Display a not found message */}

    {tErrors('notFoundMsg')}

    + {/* Provide a link to redirect users based on admin status */} {adminFor != undefined ? ( {t('backToHome')} diff --git a/src/screens/Requests/Requests.test.tsx b/src/screens/Requests/Requests.test.tsx index bf1a533870..4606fdae08 100644 --- a/src/screens/Requests/Requests.test.tsx +++ b/src/screens/Requests/Requests.test.tsx @@ -1,6 +1,6 @@ -import React from 'react'; +import React, { act } from 'react'; import { MockedProvider } from '@apollo/react-testing'; -import { act, render, screen } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import 'jest-localstorage-mock'; import 'jest-location-mock'; import { I18nextProvider } from 'react-i18next'; diff --git a/src/screens/Requests/Requests.tsx b/src/screens/Requests/Requests.tsx index a779bd414c..38bc51195e 100644 --- a/src/screens/Requests/Requests.tsx +++ b/src/screens/Requests/Requests.tsx @@ -26,14 +26,23 @@ interface InterfaceRequestsListItem { }; } +/** + * The `Requests` component fetches and displays a paginated list of membership requests + * for an organization, with functionality for searching, filtering, and infinite scrolling. + * + */ const Requests = (): JSX.Element => { + // Translation hooks for internationalization const { t } = useTranslation('translation', { keyPrefix: 'requests' }); const { t: tCommon } = useTranslation('common'); + // Set the document title to the translated title for the requests page document.title = t('title'); + // Hook for managing local storage const { getItem } = useLocalStorage(); + // Define constants and state variables const perPageResult = 8; const [isLoading, setIsLoading] = useState(true); const [hasMore, setHasMore] = useState(true); @@ -47,6 +56,7 @@ const Requests = (): JSX.Element => { const { orgId = '' } = useParams(); const organizationId = orgId; + // Query to fetch membership requests const { data, loading, fetchMore, refetch } = useQuery(MEMBERSHIP_REQUEST, { variables: { id: organizationId, @@ -57,6 +67,7 @@ const Requests = (): JSX.Element => { notifyOnNetworkStatusChange: true, }); + // Query to fetch the list of organizations const { data: orgsData } = useQuery(ORGANIZATION_CONNECTION_LIST); const [displayedRequests, setDisplayedRequests] = useState( data?.organizations[0]?.membershipRequests || [], @@ -77,25 +88,25 @@ const Requests = (): JSX.Element => { setDisplayedRequests(membershipRequests); }, [data]); - // To clear the search when the component is unmounted + // Clear the search field when the component is unmounted useEffect(() => { return () => { setSearchByName(''); }; }, []); - // Warn if there is no organization + // Show a warning if there are no organizations useEffect(() => { if (!orgsData) { return; } if (orgsData.organizationsConnection.length === 0) { - toast.warning(t('noOrgError')); + toast.warning(t('noOrgError') as string); } }, [orgsData]); - // Send to orgList page if user is not admin + // Redirect to orgList page if the user is not an admin useEffect(() => { if (userRole != 'ADMIN' && userRole != 'SUPERADMIN') { window.location.assign('/orglist'); @@ -111,6 +122,11 @@ const Requests = (): JSX.Element => { } }, [loading]); + /** + * Handles the search input change and refetches the data based on the search value. + * + * @param value - The search term entered by the user. + */ const handleSearch = (value: string): void => { setSearchByName(value); if (value === '') { @@ -124,6 +140,11 @@ const Requests = (): JSX.Element => { }); }; + /** + * Handles search input when the Enter key is pressed. + * + * @param e - The keyboard event. + */ const handleSearchByEnter = ( e: React.KeyboardEvent, ): void => { @@ -133,6 +154,9 @@ const Requests = (): JSX.Element => { } }; + /** + * Handles the search button click to trigger the search. + */ const handleSearchByBtnClick = (): void => { const inputElement = document.getElementById( 'searchRequests', @@ -141,6 +165,9 @@ const Requests = (): JSX.Element => { handleSearch(inputValue); }; + /** + * Resets search and refetches the data. + */ const resetAndRefetch = (): void => { refetch({ first: perPageResult, @@ -149,6 +176,10 @@ const Requests = (): JSX.Element => { }); setHasMore(true); }; + + /** + * Loads more requests when scrolling to the bottom of the page. + */ /* istanbul ignore next */ const loadMoreRequests = (): void => { setIsLoadingMore(true); @@ -188,6 +219,7 @@ const Requests = (): JSX.Element => { }); }; + // Header titles for the table const headerTitles: string[] = [ t('sl_no'), tCommon('name'), diff --git a/src/screens/SubTags/SubTags.module.css b/src/screens/SubTags/SubTags.module.css new file mode 100644 index 0000000000..2fed58ec52 --- /dev/null +++ b/src/screens/SubTags/SubTags.module.css @@ -0,0 +1,137 @@ +.btnsContainer { + display: flex; + margin: 2rem 0; +} + +.btnsContainer .btnsBlock { + display: flex; + width: max-content; +} + +.btnsContainer .btnsBlock button { + margin-left: 1rem; + display: flex; + justify-content: center; + align-items: center; +} + +.btnsContainer .input { + flex: 1; + position: relative; + max-width: 60%; + justify-content: space-between; +} + +.btnsContainer input { + outline: 1px solid var(--bs-gray-400); +} + +.btnsContainer .input button { + width: 52px; +} + +@media (max-width: 1020px) { + .btnsContainer { + flex-direction: column; + margin: 1.5rem 0; + } + + .btnsContainer .btnsBlock { + margin: 1.5rem 0 0 0; + justify-content: space-between; + } + + .btnsContainer .btnsBlock button { + margin: 0; + } + + .btnsContainer .btnsBlock div button { + margin-right: 1.5rem; + } +} + +/* For mobile devices */ + +@media (max-width: 520px) { + .btnsContainer { + margin-bottom: 0; + } + + .btnsContainer .btnsBlock { + display: block; + margin-top: 1rem; + margin-right: 0; + } + + .btnsContainer .btnsBlock div { + flex: 1; + } + + .btnsContainer .btnsBlock div[title='Sort organizations'] { + margin-right: 0.5rem; + } + + .btnsContainer .btnsBlock button { + margin-bottom: 1rem; + margin-right: 0; + width: 100%; + } +} + +.errorContainer { + min-height: 100vh; +} + +.errorMessage { + margin-top: 25%; + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; +} + +.errorIcon { + transform: scale(1.5); + color: var(--bs-danger); + margin-bottom: 1rem; +} + +.tableHeader { + background-color: var(--bs-primary); + color: var(--bs-white); + font-size: 1rem; +} +.rowBackground { + background-color: var(--bs-white); + max-height: 120px; +} + +.subTagsLink { + color: var(--bs-blue); + font-weight: 500; + cursor: pointer; +} + +.subTagsLink i { + visibility: hidden; +} + +.subTagsLink:hover { + font-weight: 600; + text-decoration: underline; +} + +.subTagsLink:hover i { + visibility: visible; +} + +.tagsBreadCrumbs { + color: var(--bs-gray); + cursor: pointer; +} + +.tagsBreadCrumbs:hover { + color: var(--bs-blue); + font-weight: 600; + text-decoration: underline; +} diff --git a/src/screens/SubTags/SubTags.test.tsx b/src/screens/SubTags/SubTags.test.tsx new file mode 100644 index 0000000000..1780027639 --- /dev/null +++ b/src/screens/SubTags/SubTags.test.tsx @@ -0,0 +1,325 @@ +import React from 'react'; +import { MockedProvider } from '@apollo/react-testing'; +import type { RenderResult } from '@testing-library/react'; +import { + act, + cleanup, + render, + screen, + waitFor, + waitForElementToBeRemoved, +} from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import 'jest-location-mock'; +import { I18nextProvider } from 'react-i18next'; +import { Provider } from 'react-redux'; +import { MemoryRouter, Route, Routes } from 'react-router-dom'; +import { toast } from 'react-toastify'; +import { store } from 'state/store'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import i18n from 'utils/i18nForTest'; +import SubTags from './SubTags'; +import { + MOCKS, + MOCKS_ERROR_SUB_TAGS, + MOCKS_ERROR_TAG_ANCESTORS, +} from './SubTagsMocks'; +import { InMemoryCache, type ApolloLink } from '@apollo/client'; + +const translations = { + ...JSON.parse( + JSON.stringify( + i18n.getDataByLanguage('en')?.translation.organizationTags ?? {}, + ), + ), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.common ?? {})), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.errors ?? {})), +}; + +const link = new StaticMockLink(MOCKS, true); +const link2 = new StaticMockLink(MOCKS_ERROR_SUB_TAGS, true); +const link3 = new StaticMockLink(MOCKS_ERROR_TAG_ANCESTORS, true); + +async function wait(ms = 500): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + error: jest.fn(), + }, +})); + +const cache = new InMemoryCache({ + typePolicies: { + Query: { + fields: { + getUserTag: { + keyArgs: false, + merge(existing = {}, incoming) { + return incoming; + }, + }, + }, + }, + }, +}); + +const renderSubTags = (link: ApolloLink): RenderResult => { + return render( + + + + + +
    } + /> +
    } + /> + } + /> + + + + + , + ); +}; + +describe('Organisation Tags Page', () => { + beforeEach(() => { + jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: 'orgId' }), + })); + cache.reset(); + }); + + afterEach(() => { + jest.clearAllMocks(); + cleanup(); + }); + + test('Component loads correctly', async () => { + const { getByText } = renderSubTags(link); + + await wait(); + + await waitFor(() => { + expect(getByText(translations.addChildTag)).toBeInTheDocument(); + }); + }); + + test('render error component on unsuccessful subtags query', async () => { + const { queryByText } = renderSubTags(link2); + + await wait(); + + await waitFor(() => { + expect(queryByText(translations.addChildTag)).not.toBeInTheDocument(); + }); + }); + + test('renders error component on unsuccessful userTag ancestors query', async () => { + const { queryByText } = renderSubTags(link3); + + await wait(); + + await waitFor(() => { + expect(queryByText(translations.addChildTag)).not.toBeInTheDocument(); + }); + }); + + test('opens and closes the create tag modal', async () => { + renderSubTags(link); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('addSubTagBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('addSubTagBtn')); + + await waitFor(() => { + return expect( + screen.findByTestId('addSubTagModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('addSubTagModalCloseBtn')); + + await waitForElementToBeRemoved(() => + screen.queryByTestId('addSubTagModalCloseBtn'), + ); + }); + + test('opens and closes the remove tag modal', async () => { + renderSubTags(link); + + await wait(); + + await waitFor(() => { + expect(screen.getAllByTestId('removeUserTagBtn')[0]).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('removeUserTagBtn')[0]); + + await waitFor(() => { + return expect( + screen.findByTestId('removeUserTagModalCloseBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('removeUserTagModalCloseBtn')); + + await waitForElementToBeRemoved(() => + screen.queryByTestId('removeUserTagModalCloseBtn'), + ); + }); + + test('navigates to manage tag screen after clicking manage tag option', async () => { + renderSubTags(link); + + await wait(); + + await waitFor(() => { + expect(screen.getAllByTestId('manageTagBtn')[0]).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('manageTagBtn')[0]); + + await waitFor(() => { + expect(screen.getByTestId('manageTagScreen')).toBeInTheDocument(); + }); + }); + + test('navigates to sub tags screen after clicking on a tag', async () => { + renderSubTags(link); + + await wait(); + + await waitFor(() => { + expect(screen.getAllByTestId('tagName')[0]).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('tagName')[0]); + + await waitFor(() => { + expect(screen.getByTestId('addSubTagBtn')).toBeInTheDocument(); + }); + }); + + test('navigates to the different sub tag screen screen after clicking a tag in the breadcrumbs', async () => { + renderSubTags(link); + + await wait(); + + await waitFor(() => { + expect(screen.getAllByTestId('redirectToSubTags')[0]).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('redirectToSubTags')[0]); + + await waitFor(() => { + expect(screen.getByTestId('addSubTagBtn')).toBeInTheDocument(); + }); + }); + + test('navigates to organization tags screen screen after clicking tha all tags option in the breadcrumbs', async () => { + renderSubTags(link); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('allTagsBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('allTagsBtn')); + + await waitFor(() => { + expect(screen.getByTestId('orgtagsScreen')).toBeInTheDocument(); + }); + }); + + test('navigates to manage tags screen for the current tag after clicking tha manageCurrentTag button', async () => { + renderSubTags(link); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('manageCurrentTagBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('manageCurrentTagBtn')); + + await waitFor(() => { + expect(screen.getByTestId('manageTagScreen')).toBeInTheDocument(); + }); + }); + + test('paginates between different pages', async () => { + renderSubTags(link); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('nextPagBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('nextPagBtn')); + + await waitFor(() => { + expect(screen.getAllByTestId('tagName')[0]).toHaveTextContent('subTag 6'); + }); + + await waitFor(() => { + expect(screen.getByTestId('previousPageBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('previousPageBtn')); + + await waitFor(() => { + expect(screen.getAllByTestId('tagName')[0]).toHaveTextContent('subTag 1'); + }); + }); + + test('adds a new sub tag to the current tag', async () => { + renderSubTags(link); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('addSubTagBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('addSubTagBtn')); + + userEvent.type( + screen.getByPlaceholderText(translations.tagNamePlaceholder), + 'subTag 7', + ); + + userEvent.click(screen.getByTestId('addSubTagSubmitBtn')); + + await waitFor(() => { + expect(toast.success).toBeCalledWith(translations.tagCreationSuccess); + }); + }); + + test('removes a sub tag', async () => { + renderSubTags(link); + + await wait(); + + await waitFor(() => { + expect(screen.getAllByTestId('removeUserTagBtn')[0]).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('removeUserTagBtn')[0]); + + userEvent.click(screen.getByTestId('removeUserTagSubmitBtn')); + + await waitFor(() => { + expect(toast.success).toBeCalledWith(translations.tagRemovalSuccess); + }); + }); +}); diff --git a/src/screens/SubTags/SubTags.tsx b/src/screens/SubTags/SubTags.tsx new file mode 100644 index 0000000000..b381c9f816 --- /dev/null +++ b/src/screens/SubTags/SubTags.tsx @@ -0,0 +1,572 @@ +import { useMutation, useQuery, type ApolloError } from '@apollo/client'; +import { Search, WarningAmberRounded } from '@mui/icons-material'; +import SortIcon from '@mui/icons-material/Sort'; +import Loader from 'components/Loader/Loader'; +import IconComponent from 'components/IconComponent/IconComponent'; +import { useNavigate, useParams, Link } from 'react-router-dom'; +import type { ChangeEvent } from 'react'; +import React, { useState } from 'react'; +import { Form } from 'react-bootstrap'; +import Button from 'react-bootstrap/Button'; +import Dropdown from 'react-bootstrap/Dropdown'; +import Modal from 'react-bootstrap/Modal'; +import Row from 'react-bootstrap/Row'; +import { useTranslation } from 'react-i18next'; +import { toast } from 'react-toastify'; +import type { InterfaceQueryUserTagChildTags } from 'utils/interfaces'; +import styles from './SubTags.module.css'; +import { DataGrid } from '@mui/x-data-grid'; +import { dataGridStyle } from 'utils/organizationTagsUtils'; +import type { GridCellParams, GridColDef } from '@mui/x-data-grid'; +import { Stack } from '@mui/material'; +import { + CREATE_USER_TAG, + REMOVE_USER_TAG, +} from 'GraphQl/Mutations/TagMutations'; +import { + USER_TAG_ANCESTORS, + USER_TAG_SUB_TAGS, +} from 'GraphQl/Queries/userTagQueries'; + +/** + * Component that renders the SubTags screen when the app navigates to '/orgtags/:orgId/subtags/:tagId'. + * + * This component does not accept any props and is responsible for displaying + * the content associated with the corresponding route. + */ + +function SubTags(): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'organizationTags', + }); + const { t: tCommon } = useTranslation('common'); + + const [addSubTagModalIsOpen, setAddSubTagModalIsOpen] = useState(false); + + const { orgId, tagId: parentTagId } = useParams(); + + const navigate = useNavigate(); + + const [after, setAfter] = useState(null); + const [before, setBefore] = useState(null); + const [first, setFirst] = useState(5); + const [last, setLast] = useState(null); + + const [tagName, setTagName] = useState(''); + + const [removeUserTagId, setRemoveUserTagId] = useState(null); + const [removeUserTagModalIsOpen, setRemoveUserTagModalIsOpen] = + useState(false); + + const showAddSubTagModal = (): void => { + setAddSubTagModalIsOpen(true); + }; + + const hideAddSubTagModal = (): void => { + setAddSubTagModalIsOpen(false); + setTagName(''); + }; + + const { + data: subTagsData, + loading: subTagsLoading, + error: subTagsError, + refetch: subTagsRefetch, + }: { + data?: { + getUserTag: InterfaceQueryUserTagChildTags; + }; + loading: boolean; + error?: ApolloError; + refetch: () => void; + } = useQuery(USER_TAG_SUB_TAGS, { + variables: { + id: parentTagId, + after: after, + before: before, + first: first, + last: last, + }, + }); + + const { + data: orgUserTagAncestorsData, + loading: orgUserTagsAncestorsLoading, + error: orgUserTagsAncestorsError, + }: { + data?: { + getUserTagAncestors: { + _id: string; + name: string; + }[]; + }; + loading: boolean; + error?: ApolloError; + refetch: () => void; + } = useQuery(USER_TAG_ANCESTORS, { + variables: { + id: parentTagId, + }, + }); + + const [create, { loading: createUserTagLoading }] = + useMutation(CREATE_USER_TAG); + + const addSubTag = async (e: ChangeEvent): Promise => { + e.preventDefault(); + + try { + const { data } = await create({ + variables: { + name: tagName, + organizationId: orgId, + parentTagId, + }, + }); + + /* istanbul ignore next */ + if (data) { + toast.success(t('tagCreationSuccess') as string); + subTagsRefetch(); + setTagName(''); + setAddSubTagModalIsOpen(false); + } + } catch (error: unknown) { + /* istanbul ignore next */ + if (error instanceof Error) { + toast.error(error.message); + } + } + }; + + const [removeUserTag] = useMutation(REMOVE_USER_TAG); + const handleRemoveUserTag = async (): Promise => { + try { + await removeUserTag({ + variables: { + id: removeUserTagId, + }, + }); + + subTagsRefetch(); + toggleRemoveUserTagModal(); + toast.success(t('tagRemovalSuccess') as string); + } catch (error: unknown) { + /* istanbul ignore next */ + if (error instanceof Error) { + toast.error(error.message); + } + } + }; + + if (createUserTagLoading || subTagsLoading || orgUserTagsAncestorsLoading) { + return ; + } + + const handleNextPage = (): void => { + setAfter(subTagsData?.getUserTag.childTags.pageInfo.endCursor); + setBefore(null); + setFirst(5); + setLast(null); + }; + + const handlePreviousPage = (): void => { + setBefore(subTagsData?.getUserTag.childTags.pageInfo.startCursor); + setAfter(null); + setFirst(null); + setLast(5); + }; + + if (subTagsError || orgUserTagsAncestorsError) { + return ( +
    +
    + +
    + Error occured while loading{' '} + {subTagsError ? 'sub tags' : 'tag ancestors'} +
    + {subTagsError + ? subTagsError.message + : orgUserTagsAncestorsError?.message} +
    +
    +
    + ); + } + + const userTagsList = subTagsData?.getUserTag.childTags.edges.map( + (edge) => edge.node, + ); + + const orgUserTagAncestors = orgUserTagAncestorsData?.getUserTagAncestors; + + const redirectToManageTag = (tagId: string): void => { + navigate(`/orgtags/${orgId}/manageTag/${tagId}`); + }; + + const redirectToSubTags = (tagId: string): void => { + navigate(`/orgtags/${orgId}/subtags/${tagId}`); + }; + + const toggleRemoveUserTagModal = (): void => { + if (removeUserTagModalIsOpen) { + setRemoveUserTagId(null); + } + setRemoveUserTagModalIsOpen(!removeUserTagModalIsOpen); + }; + + const columns: GridColDef[] = [ + { + field: 'id', + headerName: '#', + minWidth: 100, + align: 'center', + headerAlign: 'center', + headerClassName: `${styles.tableHeader}`, + sortable: false, + renderCell: (params: GridCellParams) => { + return
    {params.row.id}
    ; + }, + }, + { + field: 'tagName', + headerName: 'Tag Name', + flex: 1, + minWidth: 100, + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + return ( +
    redirectToSubTags(params.row._id as string)} + > + {params.row.name} + + +
    + ); + }, + }, + { + field: 'totalSubTags', + headerName: 'Total Sub Tags', + flex: 1, + align: 'center', + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + return ( + + {params.row.childTags.totalCount} + + ); + }, + }, + { + field: 'totalAssignedUsers', + headerName: 'Total Assigned Users', + flex: 1, + align: 'center', + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + return ( + + {params.row.usersAssignedTo.totalCount} + + ); + }, + }, + { + field: 'actions', + headerName: 'Actions', + flex: 1, + align: 'center', + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + return ( +
    + + + +
    + ); + }, + }, + ]; + + return ( + <> + +
    +
    +
    + + +
    +
    + + + + + +
    +
    + +
    +
    +
    + +
    + +
    navigate(`/orgtags/${orgId}`)} + className={`fs-6 ms-3 my-1 ${styles.tagsBreadCrumbs}`} + data-testid="allTagsBtn" + > + {'Tags'} + +
    + + {orgUserTagAncestors?.map((tag, index) => ( +
    redirectToSubTags(tag._id as string)} + data-testid="redirectToSubTags" + > + {tag.name} + + {orgUserTagAncestors.length - 1 !== index && ( + + )} +
    + ))} +
    + row._id} + slots={{ + noRowsOverlay: /* istanbul ignore next */ () => ( + + {t('noTagsFound')} + + ), + }} + sx={dataGridStyle} + getRowClassName={() => `${styles.rowBackground}`} + autoHeight + rowHeight={65} + rows={userTagsList?.map((fund, index) => ({ + id: index + 1, + ...fund, + }))} + columns={columns} + isRowSelectable={() => false} + /> +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    + + {/* Create Tag Modal */} + + + {t('tagDetails')} + +
    + + {t('tagName')} + { + setTagName(e.target.value); + }} + /> + + + + + + +
    +
    + + {/* Remove User Tag Modal */} + + + + {t('removeUserTag')} + + + {t('removeUserTagMessage')} + + + + + + + ); +} + +export default SubTags; diff --git a/src/screens/SubTags/SubTagsMocks.ts b/src/screens/SubTags/SubTagsMocks.ts new file mode 100644 index 0000000000..757f3f42ad --- /dev/null +++ b/src/screens/SubTags/SubTagsMocks.ts @@ -0,0 +1,415 @@ +import { + CREATE_USER_TAG, + REMOVE_USER_TAG, +} from 'GraphQl/Mutations/TagMutations'; +import { + USER_TAG_ANCESTORS, + USER_TAG_SUB_TAGS, +} from 'GraphQl/Queries/userTagQueries'; + +export const MOCKS = [ + { + request: { + query: USER_TAG_SUB_TAGS, + variables: { + id: 'tag1', + after: null, + before: null, + first: 5, + last: null, + }, + }, + result: { + data: { + getUserTag: { + name: 'tag1', + childTags: { + edges: [ + { + node: { + _id: '1', + name: 'subTag 1', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 5, + }, + }, + cursor: '1', + }, + { + node: { + _id: '2', + name: 'subTag 2', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 0, + }, + }, + cursor: '2', + }, + { + node: { + _id: '3', + name: 'subTag 3', + usersAssignedTo: { + totalCount: 0, + }, + childTags: { + totalCount: 5, + }, + }, + cursor: '3', + }, + { + node: { + _id: '4', + name: 'subTag 4', + usersAssignedTo: { + totalCount: 0, + }, + childTags: { + totalCount: 0, + }, + }, + cursor: '4', + }, + { + node: { + _id: '5', + name: 'subTag 5', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 5, + }, + }, + cursor: '5', + }, + ], + pageInfo: { + startCursor: '1', + endCursor: '5', + hasNextPage: true, + hasPreviousPage: false, + }, + totalCount: 6, + }, + }, + }, + }, + }, + { + request: { + query: USER_TAG_SUB_TAGS, + variables: { + id: 'tag1', + after: '5', + before: null, + first: 5, + last: null, + }, + }, + result: { + data: { + getUserTag: { + name: 'tag1', + childTags: { + edges: [ + { + node: { + _id: '6', + name: 'subTag 6', + usersAssignedTo: { + totalCount: 0, + }, + childTags: { + totalCount: 0, + }, + }, + cursor: '6', + }, + ], + pageInfo: { + startCursor: '6', + endCursor: '6', + hasNextPage: false, + hasPreviousPage: true, + }, + totalCount: 6, + }, + }, + }, + }, + }, + { + request: { + query: USER_TAG_SUB_TAGS, + variables: { + id: 'tag1', + after: null, + before: '6', + first: null, + last: 5, + }, + }, + result: { + data: { + getUserTag: { + name: 'tag1', + childTags: { + edges: [ + { + node: { + _id: '1', + name: 'subTag 1', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 5, + }, + }, + cursor: '1', + }, + { + node: { + _id: '2', + name: 'subTag 2', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 0, + }, + }, + cursor: '2', + }, + { + node: { + _id: '3', + name: 'subTag 3', + usersAssignedTo: { + totalCount: 0, + }, + childTags: { + totalCount: 5, + }, + }, + cursor: '3', + }, + { + node: { + _id: '4', + name: 'subTag 4', + usersAssignedTo: { + totalCount: 0, + }, + childTags: { + totalCount: 0, + }, + }, + cursor: '4', + }, + { + node: { + _id: '5', + name: 'subTag 5', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 5, + }, + }, + cursor: '5', + }, + ], + pageInfo: { + startCursor: '1', + endCursor: '5', + hasNextPage: true, + hasPreviousPage: false, + }, + totalCount: 6, + }, + }, + }, + }, + }, + { + request: { + query: USER_TAG_SUB_TAGS, + variables: { + id: '1', + after: null, + before: null, + first: 5, + last: null, + }, + }, + result: { + data: { + getUserTag: { + name: 'subTag 1', + childTags: { + edges: [], + pageInfo: { + startCursor: null, + endCursor: null, + hasNextPage: false, + hasPreviousPage: false, + }, + totalCount: 0, + }, + }, + }, + }, + }, + { + request: { + query: USER_TAG_ANCESTORS, + variables: { + id: 'tag1', + }, + }, + result: { + data: { + getUserTagAncestors: [ + { + _id: '1', + name: 'tag1', + }, + ], + }, + }, + }, + { + request: { + query: USER_TAG_ANCESTORS, + variables: { + id: '1', + }, + }, + result: { + data: { + getUserTagAncestors: [ + { + _id: 'tag1', + name: 'tag 1', + }, + { + _id: '1', + name: 'subTag 1', + }, + ], + }, + }, + }, + { + request: { + query: CREATE_USER_TAG, + variables: { + name: 'subTag 7', + organizationId: '123', + parentTagId: 'tag1', + }, + }, + result: { + data: { + createUserTag: { + _id: '7', + }, + }, + }, + }, + { + request: { + query: REMOVE_USER_TAG, + variables: { + id: '1', + }, + }, + result: { + data: { + removeUserTag: { + _id: '1', + }, + }, + }, + }, +]; + +export const MOCKS_ERROR_SUB_TAGS = [ + { + request: { + query: USER_TAG_SUB_TAGS, + variables: { + id: 'tag1', + after: null, + before: null, + first: 5, + last: null, + }, + }, + error: new Error('Mock Graphql Error'), + }, + { + request: { + query: USER_TAG_ANCESTORS, + variables: { + id: 'tag1', + }, + }, + result: { + data: { + getUserTagAncestors: [], + }, + }, + }, +]; + +export const MOCKS_ERROR_TAG_ANCESTORS = [ + { + request: { + query: USER_TAG_SUB_TAGS, + variables: { + id: 'tag1', + after: null, + before: null, + first: 5, + last: null, + }, + }, + result: { + data: { + getUserTag: { + name: 'tag1', + childTags: { + edges: [], + pageInfo: { + startCursor: '1', + endCursor: '5', + hasNextPage: true, + hasPreviousPage: false, + }, + totalCount: 6, + }, + }, + }, + }, + }, + { + request: { + query: USER_TAG_ANCESTORS, + variables: { + id: 'tag1', + }, + }, + error: new Error('Mock Graphql Error'), + }, +]; diff --git a/src/screens/UserPortal/Campaigns/Campaigns.module.css b/src/screens/UserPortal/Campaigns/Campaigns.module.css new file mode 100644 index 0000000000..b535b9981c --- /dev/null +++ b/src/screens/UserPortal/Campaigns/Campaigns.module.css @@ -0,0 +1,137 @@ +.btnsContainer { + display: flex; + margin: 1.5rem 0; +} + +.btnsContainer .input { + flex: 1; + min-width: 18rem; + position: relative; +} + +.btnsContainer input { + outline: 1px solid var(--bs-gray-400); + background-color: white; +} + +.btnsContainer .input button { + width: 52px; +} + +.accordionSummary { + width: 100% !important; + padding-right: 0.75rem; + display: flex; + justify-content: space-between !important; + align-items: center; +} + +.accordionSummary button { + height: 2.25rem; + padding-top: 0.35rem; +} + +.accordionSummary button:hover { + background-color: #31bb6a50 !important; + color: #31bb6b !important; +} + +.titleContainer { + display: flex; + flex-direction: column; + gap: 0.1rem; +} + +.titleContainer h3 { + font-size: 1.25rem; + font-weight: 750; + color: #5e5e5e; + margin-top: 0.2rem; +} + +.subContainer span { + font-size: 0.9rem; + margin-left: 0.5rem; + font-weight: lighter; + color: #707070; +} + +.chipIcon { + height: 0.9rem !important; +} + +.chip { + height: 1.5rem !important; + margin: 0.15rem 0 0 1.25rem; +} + +.active { + background-color: #31bb6a50 !important; +} + +.pending { + background-color: #ffd76950 !important; + color: #bb952bd0 !important; + border-color: #bb952bd0 !important; +} + +.progress { + display: flex; + width: 45rem; +} + +.progressBar { + margin: 0rem 0.75rem; + width: 100%; + font-size: 0.9rem; + height: 1.25rem; +} + +/* Pledge Modal */ + +.pledgeModal { + max-width: 80vw; + margin-top: 2vh; + margin-left: 13vw; +} + +.titlemodal { + color: #707070; + font-weight: 600; + font-size: 32px; + width: 65%; + margin-bottom: 0px; +} + +.modalCloseBtn { + width: 40px; + height: 40px; + padding: 1rem; + display: flex; + justify-content: center; + align-items: center; +} + +.noOutline input { + outline: none; +} + +.greenregbtn { + margin: 1rem 0 0; + margin-top: 15px; + border: 1px solid #e8e5e5; + box-shadow: 0 2px 2px #e8e5e5; + padding: 10px 10px; + border-radius: 5px; + background-color: #31bb6b; + width: 100%; + font-size: 16px; + color: white; + outline: none; + font-weight: 600; + cursor: pointer; + transition: + transform 0.2s, + box-shadow 0.2s; + width: 100%; +} diff --git a/src/screens/UserPortal/Campaigns/Campaigns.test.tsx b/src/screens/UserPortal/Campaigns/Campaigns.test.tsx new file mode 100644 index 0000000000..17b7eec4d5 --- /dev/null +++ b/src/screens/UserPortal/Campaigns/Campaigns.test.tsx @@ -0,0 +1,324 @@ +import React from 'react'; +import { MockedProvider } from '@apollo/react-testing'; +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import type { RenderResult } from '@testing-library/react'; +import { + cleanup, + fireEvent, + render, + screen, + waitFor, +} from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { I18nextProvider } from 'react-i18next'; +import { Provider } from 'react-redux'; +import { MemoryRouter, Route, Routes } from 'react-router-dom'; +import { store } from 'state/store'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import i18nForTest from 'utils/i18nForTest'; +import type { ApolloLink } from '@apollo/client'; +import useLocalStorage from 'utils/useLocalstorage'; +import Campaigns from './Campaigns'; +import { + EMPTY_MOCKS, + MOCKS, + USER_FUND_CAMPAIGNS_ERROR, +} from './CampaignsMocks'; + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + error: jest.fn(), + }, +})); +jest.mock('@mui/x-date-pickers/DateTimePicker', () => { + return { + DateTimePicker: jest.requireActual( + '@mui/x-date-pickers/DesktopDateTimePicker', + ).DesktopDateTimePicker, + }; +}); +const { setItem } = useLocalStorage(); + +const link1 = new StaticMockLink(MOCKS); +const link2 = new StaticMockLink(USER_FUND_CAMPAIGNS_ERROR); +const link3 = new StaticMockLink(EMPTY_MOCKS); +const cTranslations = JSON.parse( + JSON.stringify( + i18nForTest.getDataByLanguage('en')?.translation.userCampaigns, + ), +); +const pTranslations = JSON.parse( + JSON.stringify(i18nForTest.getDataByLanguage('en')?.translation.pledges), +); + +const renderCampaigns = (link: ApolloLink): RenderResult => { + return render( + + + + + + + } /> +
    } + /> +
    } + /> + + + + + + , + ); +}; + +describe('Testing User Campaigns Screen', () => { + beforeEach(() => { + setItem('userId', 'userId'); + }); + + beforeAll(() => { + jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: 'orgId' }), + })); + }); + + afterAll(() => { + jest.clearAllMocks(); + }); + + afterEach(() => { + cleanup(); + }); + + it('should render the User Campaigns screen', async () => { + renderCampaigns(link1); + await waitFor(() => { + expect(screen.getByTestId('searchCampaigns')).toBeInTheDocument(); + expect(screen.getByText('School Campaign')).toBeInTheDocument(); + expect(screen.getByText('Hospital Campaign')).toBeInTheDocument(); + }); + }); + + it('should redirect to fallback URL if userId is null in LocalStorage', async () => { + setItem('userId', null); + renderCampaigns(link1); + await waitFor(() => { + expect(screen.getByTestId('paramsError')).toBeInTheDocument(); + }); + }); + + it('should redirect to fallback URL if URL params are undefined', async () => { + render( + + + + + + } /> +
    } + /> + + + + + , + ); + await waitFor(() => { + expect(screen.getByTestId('paramsError')).toBeInTheDocument(); + }); + }); + + it('should render the User Campaign screen with error', async () => { + renderCampaigns(link2); + await waitFor(() => { + expect(screen.getByTestId('errorMsg')).toBeInTheDocument(); + }); + }); + + it('renders the empty campaign component', async () => { + renderCampaigns(link3); + await waitFor(() => + expect(screen.getByText(cTranslations.noCampaigns)).toBeInTheDocument(), + ); + }); + + it('Check if All details are rendered correctly', async () => { + renderCampaigns(link1); + + const detailContainer = await screen.findByTestId('detailContainer1'); + const detailContainer2 = await screen.findByTestId('detailContainer2'); + await waitFor(() => { + expect(detailContainer).toBeInTheDocument(); + expect(detailContainer2).toBeInTheDocument(); + expect(detailContainer).toHaveTextContent('School Campaign'); + expect(detailContainer).toHaveTextContent('$22000'); + expect(detailContainer).toHaveTextContent('2024-07-28'); + expect(detailContainer).toHaveTextContent('2025-08-31'); + expect(detailContainer).toHaveTextContent('Active'); + expect(detailContainer2).toHaveTextContent('Hospital Campaign'); + expect(detailContainer2).toHaveTextContent('$9000'); + expect(detailContainer2).toHaveTextContent('2024-07-28'); + expect(detailContainer2).toHaveTextContent('2022-08-30'); + expect(detailContainer2).toHaveTextContent('Ended'); + }); + }); + + it('Sort the Campaigns list by lowest fundingGoal', async () => { + renderCampaigns(link1); + + const searchCampaigns = await screen.findByTestId('searchCampaigns'); + expect(searchCampaigns).toBeInTheDocument(); + + userEvent.click(screen.getByTestId('filter')); + await waitFor(() => { + expect(screen.getByTestId('fundingGoal_ASC')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('fundingGoal_ASC')); + + await waitFor(() => { + expect(screen.getByText('School Campaign')).toBeInTheDocument(); + expect(screen.getByText('Hospital Campaign')).toBeInTheDocument(); + }); + + await waitFor(() => { + const detailContainer = screen.getByTestId('detailContainer2'); + expect(detailContainer).toHaveTextContent('School Campaign'); + expect(detailContainer).toHaveTextContent('$22000'); + expect(detailContainer).toHaveTextContent('2024-07-28'); + expect(detailContainer).toHaveTextContent('2024-08-31'); + }); + }); + + it('Sort the Campaigns list by highest fundingGoal', async () => { + renderCampaigns(link1); + + const searchCampaigns = await screen.findByTestId('searchCampaigns'); + expect(searchCampaigns).toBeInTheDocument(); + + userEvent.click(screen.getByTestId('filter')); + await waitFor(() => { + expect(screen.getByTestId('fundingGoal_DESC')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('fundingGoal_DESC')); + + await waitFor(() => { + expect(screen.getByText('School Campaign')).toBeInTheDocument(); + expect(screen.getByText('Hospital Campaign')).toBeInTheDocument(); + }); + + await waitFor(() => { + const detailContainer = screen.getByTestId('detailContainer1'); + expect(detailContainer).toHaveTextContent('School Campaign'); + expect(detailContainer).toHaveTextContent('$22000'); + expect(detailContainer).toHaveTextContent('2024-07-28'); + expect(detailContainer).toHaveTextContent('2024-08-31'); + }); + }); + + it('Sort the Campaigns list by earliest endDate', async () => { + renderCampaigns(link1); + + const searchCampaigns = await screen.findByTestId('searchCampaigns'); + expect(searchCampaigns).toBeInTheDocument(); + + userEvent.click(screen.getByTestId('filter')); + await waitFor(() => { + expect(screen.getByTestId('endDate_ASC')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('endDate_ASC')); + + await waitFor(() => { + expect(screen.getByText('School Campaign')).toBeInTheDocument(); + expect(screen.getByText('Hospital Campaign')).toBeInTheDocument(); + }); + + await waitFor(() => { + const detailContainer = screen.getByTestId('detailContainer2'); + expect(detailContainer).toHaveTextContent('School Campaign'); + expect(detailContainer).toHaveTextContent('$22000'); + expect(detailContainer).toHaveTextContent('2024-07-28'); + expect(detailContainer).toHaveTextContent('2024-08-31'); + }); + }); + + it('Sort the Campaigns list by latest endDate', async () => { + renderCampaigns(link1); + + const searchCampaigns = await screen.findByTestId('searchCampaigns'); + expect(searchCampaigns).toBeInTheDocument(); + + userEvent.click(screen.getByTestId('filter')); + await waitFor(() => { + expect(screen.getByTestId('endDate_DESC')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('endDate_DESC')); + + await waitFor(() => { + expect(screen.getByText('School Campaign')).toBeInTheDocument(); + expect(screen.getByText('Hospital Campaign')).toBeInTheDocument(); + }); + + await waitFor(() => { + const detailContainer = screen.getByTestId('detailContainer1'); + expect(detailContainer).toHaveTextContent('School Campaign'); + expect(detailContainer).toHaveTextContent('$22000'); + expect(detailContainer).toHaveTextContent('2024-07-28'); + expect(detailContainer).toHaveTextContent('2025-08-31'); + }); + }); + + it('Search the Campaigns list by name', async () => { + renderCampaigns(link1); + + const searchCampaigns = await screen.findByTestId('searchCampaigns'); + expect(searchCampaigns).toBeInTheDocument(); + + fireEvent.change(searchCampaigns, { + target: { value: 'Hospital' }, + }); + + await waitFor(() => { + expect(screen.queryByText('School Campaign')).toBeNull(); + expect(screen.getByText('Hospital Campaign')).toBeInTheDocument(); + }); + }); + + it('open and closes add pledge modal', async () => { + renderCampaigns(link1); + + const addPledgeBtn = await screen.findAllByTestId('addPledgeBtn'); + await waitFor(() => expect(addPledgeBtn[0]).toBeInTheDocument()); + userEvent.click(addPledgeBtn[0]); + + await waitFor(() => + expect(screen.getAllByText(pTranslations.createPledge)).toHaveLength(2), + ); + userEvent.click(screen.getByTestId('pledgeModalCloseBtn')); + await waitFor(() => + expect(screen.queryByTestId('pledgeModalCloseBtn')).toBeNull(), + ); + }); + + it('Redirect to My Pledges screen', async () => { + renderCampaigns(link1); + + const myPledgesBtn = await screen.findByText(cTranslations.myPledges); + expect(myPledgesBtn).toBeInTheDocument(); + userEvent.click(myPledgesBtn); + + await waitFor(() => { + expect(screen.getByTestId('pledgeScreen')).toBeInTheDocument(); + }); + }); +}); diff --git a/src/screens/UserPortal/Campaigns/Campaigns.tsx b/src/screens/UserPortal/Campaigns/Campaigns.tsx new file mode 100644 index 0000000000..e4483f87fe --- /dev/null +++ b/src/screens/UserPortal/Campaigns/Campaigns.tsx @@ -0,0 +1,305 @@ +import React, { useEffect, useState } from 'react'; +import { Dropdown, Form, Button, ProgressBar } from 'react-bootstrap'; +import styles from './Campaigns.module.css'; +import { useTranslation } from 'react-i18next'; +import { Navigate, useNavigate, useParams } from 'react-router-dom'; +import { Circle, Search, Sort, WarningAmberRounded } from '@mui/icons-material'; +import { + Accordion, + AccordionDetails, + AccordionSummary, + Chip, + Stack, +} from '@mui/material'; +import { GridExpandMoreIcon } from '@mui/x-data-grid'; +import useLocalStorage from 'utils/useLocalstorage'; +import PledgeModal from './PledgeModal'; +import { USER_FUND_CAMPAIGNS } from 'GraphQl/Queries/fundQueries'; +import { useQuery } from '@apollo/client'; +import type { InterfaceUserCampaign } from 'utils/interfaces'; +import { currencySymbols } from 'utils/currency'; +import Loader from 'components/Loader/Loader'; + +/** + * The `Campaigns` component displays a list of fundraising campaigns for a specific organization. + * It allows users to search, sort, and view details about each campaign. Users can also add pledges to active campaigns. + * + * @returns The rendered component displaying the campaigns. + */ +const Campaigns = (): JSX.Element => { + // Retrieves translation functions for various namespaces + const { t } = useTranslation('translation', { + keyPrefix: 'userCampaigns', + }); + const { t: tCommon } = useTranslation('common'); + const { t: tErrors } = useTranslation('errors'); + + // Retrieves stored user ID from local storage + const { getItem } = useLocalStorage(); + const userId = getItem('userId'); + + // Extracts organization ID from the URL parameters + const { orgId } = useParams(); + if (!orgId || !userId) { + // Redirects to the homepage if orgId or userId is missing + return ; + } + + // Navigation hook to programmatically navigate between routes + const navigate = useNavigate(); + + // State for managing search term, campaigns, selected campaign, modal state, and sorting order + const [searchTerm, setSearchTerm] = useState(''); + const [campaigns, setCampaigns] = useState([]); + const [selectedCampaign, setSelectedCampaign] = + useState(null); + const [modalState, setModalState] = useState(false); + const [sortBy, setSortBy] = useState< + 'fundingGoal_ASC' | 'fundingGoal_DESC' | 'endDate_ASC' | 'endDate_DESC' + >('endDate_DESC'); + + // Fetches campaigns based on the organization ID, search term, and sorting order + const { + data: campaignData, + loading: campaignLoading, + error: campaignError, + refetch: refetchCampaigns, + }: { + data?: { + getFundraisingCampaigns: InterfaceUserCampaign[]; + }; + loading: boolean; + error?: Error | undefined; + refetch: () => void; + } = useQuery(USER_FUND_CAMPAIGNS, { + variables: { + where: { + organizationId: orgId, + name_contains: searchTerm, + }, + campaignOrderBy: sortBy, + }, + }); + + /** + * Opens the modal for adding a pledge to a selected campaign. + * + * @param campaign - The campaign to which the user wants to add a pledge. + */ + const openModal = (campaign: InterfaceUserCampaign): void => { + setSelectedCampaign(campaign); + setModalState(true); + }; + + /** + * Closes the modal and clears the selected campaign. + */ + const closeModal = (): void => { + setModalState(false); + setSelectedCampaign(null); + }; + + // Updates the campaigns state when the fetched campaign data changes + useEffect(() => { + if (campaignData) { + setCampaigns(campaignData.getFundraisingCampaigns); + } + }, [campaignData]); + + // Renders a loader while campaigns are being fetched + if (campaignLoading) return ; + if (campaignError) { + // Displays an error message if there is an issue loading the campaigns + return ( +
    +
    + +
    + {tErrors('errorLoading', { entity: 'Campaigns' })} +
    + {campaignError.message} +
    +
    +
    + ); + } + + // Renders the campaign list and UI elements for searching, sorting, and adding pledges + return ( + <> +
    + {/* Search input field and button */} +
    + setSearchTerm(e.target.value)} + data-testid="searchCampaigns" + /> + +
    +
    +
    + {/* Dropdown menu for sorting campaigns */} + + + + {tCommon('sort')} + + + setSortBy('fundingGoal_ASC')} + data-testid="fundingGoal_ASC" + > + {t('lowestGoal')} + + setSortBy('fundingGoal_DESC')} + data-testid="fundingGoal_DESC" + > + {t('highestGoal')} + + setSortBy('endDate_DESC')} + data-testid="endDate_DESC" + > + {t('latestEndDate')} + + setSortBy('endDate_ASC')} + data-testid="endDate_ASC" + > + {t('earliestEndDate')} + + + +
    +
    + {/* Button to navigate to the user's pledges */} + +
    +
    +
    + {campaigns.length < 1 ? ( + + {/* Displayed if no campaigns are found */} + {t('noCampaigns')} + + ) : ( + campaigns.map((campaign: InterfaceUserCampaign, index: number) => ( + + }> +
    +
    +
    +

    {campaign.name}

    + } + label={ + new Date(campaign.endDate) < new Date() + ? 'Ended' + : 'Active' + } + variant="outlined" + color="primary" + className={`${styles.chip} ${new Date(campaign.endDate) < new Date() ? styles.pending : styles.active}`} + /> +
    + +
    + + Goal:{' '} + { + currencySymbols[ + campaign.currency as keyof typeof currencySymbols + ] + } + {campaign.fundingGoal} + + Raised: $0 + + Start Date: {campaign.startDate as unknown as string} + + + End Date: {campaign.endDate as unknown as string} + +
    +
    +
    + +
    +
    +
    + + Amount Raised: +
    + $0 + + $1000 +
    +
    +
    + )) + )} + + {/* Modal for adding pledges to campaigns */} + + + ); +}; + +export default Campaigns; diff --git a/src/screens/UserPortal/Campaigns/CampaignsMocks.ts b/src/screens/UserPortal/Campaigns/CampaignsMocks.ts new file mode 100644 index 0000000000..f64401bca5 --- /dev/null +++ b/src/screens/UserPortal/Campaigns/CampaignsMocks.ts @@ -0,0 +1,272 @@ +import { USER_DETAILS } from 'GraphQl/Queries/Queries'; +import { USER_FUND_CAMPAIGNS } from 'GraphQl/Queries/fundQueries'; + +const userDetailsQuery = { + request: { + query: USER_DETAILS, + variables: { + id: 'userId', + }, + }, + result: { + data: { + user: { + user: { + _id: 'userId', + joinedOrganizations: [ + { + _id: '6537904485008f171cf29924', + __typename: 'Organization', + }, + ], + firstName: 'Harve', + lastName: 'Lance', + email: 'testuser1@example.com', + image: null, + createdAt: '2023-04-13T04:53:17.742Z', + birthDate: null, + educationGrade: null, + employmentStatus: null, + gender: null, + maritalStatus: null, + phone: null, + address: { + line1: 'Line1', + countryCode: 'CountryCode', + city: 'CityName', + state: 'State', + __typename: 'Address', + }, + registeredEvents: [], + membershipRequests: [], + __typename: 'User', + }, + appUserProfile: { + _id: '67078abd85008f171cf2991d', + adminFor: [], + isSuperAdmin: false, + appLanguageCode: 'en', + pluginCreationAllowed: true, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + __typename: 'AppUserProfile', + }, + __typename: 'UserData', + }, + }, + }, +}; + +export const MOCKS = [ + { + request: { + query: USER_FUND_CAMPAIGNS, + variables: { + where: { + organizationId: 'orgId', + name_contains: '', + }, + campaignOrderBy: 'endDate_DESC', + }, + }, + result: { + data: { + getFundraisingCampaigns: [ + { + _id: 'campaignId1', + startDate: '2024-07-28', + endDate: '2025-08-31', + name: 'School Campaign', + fundingGoal: 22000, + currency: 'USD', + __typename: 'FundraisingCampaign', + }, + { + _id: 'campaignId2', + startDate: '2024-07-28', + endDate: '2022-08-30', + name: 'Hospital Campaign', + fundingGoal: 9000, + currency: 'USD', + __typename: 'FundraisingCampaign', + }, + ], + }, + }, + }, + { + request: { + query: USER_FUND_CAMPAIGNS, + variables: { + where: { + organizationId: 'orgId', + name_contains: '', + }, + campaignOrderBy: 'endDate_ASC', + }, + }, + result: { + data: { + getFundraisingCampaigns: [ + { + _id: 'campaignId2', + startDate: '2024-07-28', + endDate: '2024-08-30', + name: 'Hospital Campaign', + fundingGoal: 9000, + currency: 'USD', + __typename: 'FundraisingCampaign', + }, + { + _id: 'campaignId1', + startDate: '2024-07-28', + endDate: '2024-08-31', + name: 'School Campaign', + fundingGoal: 22000, + currency: 'USD', + __typename: 'FundraisingCampaign', + }, + ], + }, + }, + }, + { + request: { + query: USER_FUND_CAMPAIGNS, + variables: { + where: { + organizationId: 'orgId', + name_contains: '', + }, + campaignOrderBy: 'fundingGoal_ASC', + }, + }, + result: { + data: { + getFundraisingCampaigns: [ + { + _id: 'campaignId2', + startDate: '2024-07-28', + endDate: '2024-08-30', + name: 'Hospital Campaign', + fundingGoal: 9000, + currency: 'USD', + __typename: 'FundraisingCampaign', + }, + { + _id: 'campaignId1', + startDate: '2024-07-28', + endDate: '2024-08-31', + name: 'School Campaign', + fundingGoal: 22000, + currency: 'USD', + __typename: 'FundraisingCampaign', + }, + ], + }, + }, + }, + { + request: { + query: USER_FUND_CAMPAIGNS, + variables: { + where: { + organizationId: 'orgId', + name_contains: '', + }, + campaignOrderBy: 'fundingGoal_DESC', + }, + }, + result: { + data: { + getFundraisingCampaigns: [ + { + _id: 'campaignId1', + startDate: '2024-07-28', + endDate: '2024-08-31', + name: 'School Campaign', + fundingGoal: 22000, + currency: 'USD', + __typename: 'FundraisingCampaign', + }, + { + _id: 'campaignId2', + startDate: '2024-07-28', + endDate: '2024-08-30', + name: 'Hospital Campaign', + fundingGoal: 9000, + currency: 'USD', + __typename: 'FundraisingCampaign', + }, + ], + }, + }, + }, + { + request: { + query: USER_FUND_CAMPAIGNS, + variables: { + where: { + organizationId: 'orgId', + name_contains: 'Hospital', + }, + campaignOrderBy: 'endDate_DESC', + }, + }, + result: { + data: { + getFundraisingCampaigns: [ + { + _id: 'campaignId2', + startDate: '2024-07-28', + endDate: '2024-08-30', + name: 'Hospital Campaign', + fundingGoal: 9000, + currency: 'USD', + __typename: 'FundraisingCampaign', + }, + ], + }, + }, + }, + userDetailsQuery, +]; + +export const EMPTY_MOCKS = [ + { + request: { + query: USER_FUND_CAMPAIGNS, + variables: { + where: { + organizationId: 'orgId', + name_contains: '', + }, + campaignOrderBy: 'endDate_DESC', + }, + }, + result: { + data: { + getFundraisingCampaigns: [], + }, + }, + }, + userDetailsQuery, +]; + +export const USER_FUND_CAMPAIGNS_ERROR = [ + { + request: { + query: USER_FUND_CAMPAIGNS, + variables: { + where: { + organizationId: 'orgId', + name_contains: '', + }, + campaignOrderBy: 'endDate_DESC', + }, + }, + error: new Error('Error fetching campaigns'), + }, + userDetailsQuery, +]; diff --git a/src/screens/UserPortal/Campaigns/PledgeModal.test.tsx b/src/screens/UserPortal/Campaigns/PledgeModal.test.tsx new file mode 100644 index 0000000000..3f299c5c48 --- /dev/null +++ b/src/screens/UserPortal/Campaigns/PledgeModal.test.tsx @@ -0,0 +1,310 @@ +import type { ApolloLink } from '@apollo/client'; +import { MockedProvider } from '@apollo/react-testing'; +import { LocalizationProvider } from '@mui/x-date-pickers'; +import type { RenderResult } from '@testing-library/react'; +import { + cleanup, + fireEvent, + render, + screen, + waitFor, +} from '@testing-library/react'; +import { I18nextProvider } from 'react-i18next'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; +import { store } from 'state/store'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import i18nForTest from 'utils/i18nForTest'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import { toast } from 'react-toastify'; +import type { InterfacePledgeModal } from './PledgeModal'; +import PledgeModal from './PledgeModal'; +import React from 'react'; +import { USER_DETAILS } from 'GraphQl/Queries/Queries'; +import { CREATE_PlEDGE, UPDATE_PLEDGE } from 'GraphQl/Mutations/PledgeMutation'; + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + error: jest.fn(), + }, +})); + +jest.mock('@mui/x-date-pickers/DateTimePicker', () => { + return { + DateTimePicker: jest.requireActual( + '@mui/x-date-pickers/DesktopDateTimePicker', + ).DesktopDateTimePicker, + }; +}); + +const pledgeProps: InterfacePledgeModal[] = [ + { + isOpen: true, + hide: jest.fn(), + pledge: { + _id: '1', + amount: 100, + currency: 'USD', + startDate: '2024-01-01', + endDate: '2024-01-10', + users: [ + { + _id: '1', + firstName: 'John', + lastName: 'Doe', + image: null, + }, + ], + }, + refetchPledge: jest.fn(), + campaignId: 'campaignId', + userId: 'userId', + endDate: new Date(), + mode: 'create', + }, + { + isOpen: true, + hide: jest.fn(), + pledge: { + _id: '1', + amount: 100, + currency: 'USD', + startDate: '2024-01-01', + endDate: '2024-01-10', + users: [ + { + _id: '1', + firstName: 'John', + lastName: 'Doe', + image: null, + }, + ], + }, + refetchPledge: jest.fn(), + campaignId: 'campaignId', + userId: 'userId', + endDate: new Date(), + mode: 'edit', + }, +]; + +const PLEDGE_MODAL_MOCKS = [ + { + request: { + query: USER_DETAILS, + variables: { + id: 'userId', + }, + }, + result: { + data: { + user: { + user: { + _id: 'userId', + joinedOrganizations: [ + { + _id: '6537904485008f171cf29924', + __typename: 'Organization', + }, + ], + firstName: 'Harve', + lastName: 'Lance', + email: 'testuser1@example.com', + image: null, + createdAt: '2023-04-13T04:53:17.742Z', + birthDate: null, + educationGrade: null, + employmentStatus: null, + gender: null, + maritalStatus: null, + phone: null, + address: { + line1: 'Line1', + countryCode: 'CountryCode', + city: 'CityName', + state: 'State', + __typename: 'Address', + }, + registeredEvents: [], + membershipRequests: [], + __typename: 'User', + }, + appUserProfile: { + _id: '67078abd85008f171cf2991d', + adminFor: [], + isSuperAdmin: false, + appLanguageCode: 'en', + pluginCreationAllowed: true, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + __typename: 'AppUserProfile', + }, + __typename: 'UserData', + }, + }, + }, + }, + { + request: { + query: UPDATE_PLEDGE, + variables: { + id: '1', + amount: 200, + }, + }, + result: { + data: { + updateFundraisingCampaignPledge: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: CREATE_PlEDGE, + variables: { + campaignId: 'campaignId', + amount: 200, + currency: 'USD', + startDate: '2024-01-02', + endDate: '2024-01-02', + userIds: ['1'], + }, + }, + result: { + data: { + createFundraisingCampaignPledge: { + _id: '3', + }, + }, + }, + }, +]; + +const link1 = new StaticMockLink(PLEDGE_MODAL_MOCKS); +const translations = JSON.parse( + JSON.stringify(i18nForTest.getDataByLanguage('en')?.translation.pledges), +); + +const renderPledgeModal = ( + link: ApolloLink, + props: InterfacePledgeModal, +): RenderResult => { + return render( + + + + + + + + + + + , + ); +}; + +describe('PledgeModal', () => { + beforeAll(() => { + jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: 'orgId', fundCampaignId: 'fundCampaignId' }), + })); + }); + + afterAll(() => { + jest.clearAllMocks(); + }); + + afterEach(() => { + cleanup(); + }); + it('should populate form fields with correct values in edit mode', async () => { + renderPledgeModal(link1, pledgeProps[1]); + await waitFor(() => + expect(screen.getByText(translations.editPledge)).toBeInTheDocument(), + ); + expect(screen.getByTestId('pledgerSelect')).toHaveTextContent('John Doe'); + expect(screen.getByLabelText('Start Date')).toHaveValue('01/01/2024'); + expect(screen.getByLabelText('End Date')).toHaveValue('10/01/2024'); + expect(screen.getByLabelText('Currency')).toHaveTextContent('USD ($)'); + expect(screen.getByLabelText('Amount')).toHaveValue('100'); + }); + + it('should update pledgeAmount when input value changes', async () => { + renderPledgeModal(link1, pledgeProps[1]); + const amountInput = screen.getByLabelText('Amount'); + expect(amountInput).toHaveValue('100'); + fireEvent.change(amountInput, { target: { value: '200' } }); + expect(amountInput).toHaveValue('200'); + }); + + it('should not update pledgeAmount when input value is less than or equal to 0', async () => { + renderPledgeModal(link1, pledgeProps[1]); + const amountInput = screen.getByLabelText('Amount'); + expect(amountInput).toHaveValue('100'); + fireEvent.change(amountInput, { target: { value: '-10' } }); + expect(amountInput).toHaveValue('100'); + }); + + it('should update pledgeStartDate when a new date is selected', async () => { + renderPledgeModal(link1, pledgeProps[1]); + const startDateInput = screen.getByLabelText('Start Date'); + fireEvent.change(startDateInput, { target: { value: '02/01/2024' } }); + expect(startDateInput).toHaveValue('02/01/2024'); + expect(pledgeProps[1].pledge?.startDate).toEqual('2024-01-01'); + }); + + it('pledgeStartDate onChange when its null', async () => { + renderPledgeModal(link1, pledgeProps[1]); + const startDateInput = screen.getByLabelText('Start Date'); + fireEvent.change(startDateInput, { target: { value: null } }); + expect(pledgeProps[1].pledge?.startDate).toEqual('2024-01-01'); + }); + + it('should update pledgeEndDate when a new date is selected', async () => { + renderPledgeModal(link1, pledgeProps[1]); + const startDateInput = screen.getByLabelText('End Date'); + fireEvent.change(startDateInput, { target: { value: '02/01/2024' } }); + expect(startDateInput).toHaveValue('02/01/2024'); + expect(pledgeProps[1].pledge?.endDate).toEqual('2024-01-10'); + }); + + it('pledgeEndDate onChange when its null', async () => { + renderPledgeModal(link1, pledgeProps[1]); + const endDateInput = screen.getByLabelText('End Date'); + fireEvent.change(endDateInput, { target: { value: null } }); + expect(pledgeProps[1].pledge?.endDate).toEqual('2024-01-10'); + }); + + it('should create pledge', async () => { + renderPledgeModal(link1, pledgeProps[0]); + + fireEvent.change(screen.getByLabelText('Amount'), { + target: { value: '200' }, + }); + fireEvent.change(screen.getByLabelText('Start Date'), { + target: { value: '02/01/2024' }, + }); + fireEvent.change(screen.getByLabelText('End Date'), { + target: { value: '02/01/2024' }, + }); + + expect(screen.getByLabelText('Amount')).toHaveValue('200'); + expect(screen.getByLabelText('Start Date')).toHaveValue('02/01/2024'); + expect(screen.getByLabelText('End Date')).toHaveValue('02/01/2024'); + expect(screen.getByTestId('submitPledgeBtn')).toBeInTheDocument(); + + fireEvent.click(screen.getByTestId('submitPledgeBtn')); + + await waitFor(() => { + expect(toast.success).toHaveBeenCalled(); + expect(pledgeProps[0].refetchPledge).toHaveBeenCalled(); + expect(pledgeProps[0].hide).toHaveBeenCalled(); + }); + }); +}); diff --git a/src/screens/UserPortal/Campaigns/PledgeModal.tsx b/src/screens/UserPortal/Campaigns/PledgeModal.tsx new file mode 100644 index 0000000000..d9076f52c8 --- /dev/null +++ b/src/screens/UserPortal/Campaigns/PledgeModal.tsx @@ -0,0 +1,373 @@ +import { DatePicker } from '@mui/x-date-pickers'; +import dayjs, { type Dayjs } from 'dayjs'; +import type { ChangeEvent } from 'react'; +import { Button, Form, Modal } from 'react-bootstrap'; +import { currencyOptions, currencySymbols } from 'utils/currency'; +import type { + InterfaceCreatePledge, + InterfacePledgeInfo, + InterfacePledger, +} from 'utils/interfaces'; +import styles from './Campaigns.module.css'; +import React, { useCallback, useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { useMutation, useQuery } from '@apollo/client'; +import { CREATE_PlEDGE, UPDATE_PLEDGE } from 'GraphQl/Mutations/PledgeMutation'; +import { toast } from 'react-toastify'; +import { + Autocomplete, + FormControl, + InputLabel, + MenuItem, + Select, + TextField, +} from '@mui/material'; +import { USER_DETAILS } from 'GraphQl/Queries/Queries'; + +/** + * Interface representing the properties for the `PledgeModal` component. + */ +export interface InterfacePledgeModal { + isOpen: boolean; + hide: () => void; + campaignId: string; + userId: string; + pledge: InterfacePledgeInfo | null; + refetchPledge: () => void; + endDate: Date; + mode: 'create' | 'edit'; +} + +/** + * `PledgeModal` is a React component that allows users to create or edit a pledge for a specific campaign. + * It displays a form with inputs for pledge details such as amount, currency, dates, and users involved in the pledge. + * + * @param isOpen - Determines if the modal is visible or hidden. + * @param hide - Function to close the modal. + * @param campaignId - The ID of the campaign for which the pledge is being made. + * @param userId - The ID of the user making or editing the pledge. + * @param pledge - The current pledge information if in edit mode, or null if creating a new pledge. + * @param refetchPledge - Function to refresh the pledge data after a successful operation. + * @param endDate - The maximum date allowed for the pledge's end date, based on the campaign's end date. + * @param mode - Specifies whether the modal is used for creating a new pledge or editing an existing one. + */ +const PledgeModal: React.FC = ({ + isOpen, + hide, + campaignId, + userId, + pledge, + refetchPledge, + endDate, + mode, +}) => { + // Translation functions to support internationalization + const { t } = useTranslation('translation', { + keyPrefix: 'pledges', + }); + const { t: tCommon } = useTranslation('common'); + + // State to manage the form inputs for the pledge + const [formState, setFormState] = useState({ + pledgeUsers: [], + pledgeAmount: pledge?.amount ?? 0, + pledgeCurrency: pledge?.currency ?? 'USD', + pledgeEndDate: new Date(pledge?.endDate ?? new Date()), + pledgeStartDate: new Date(pledge?.startDate ?? new Date()), + }); + + // State to manage the list of pledgers (users who are part of the pledge) + const [pledgers, setPledgers] = useState([]); + + // Mutation to update an existing pledge + const [updatePledge] = useMutation(UPDATE_PLEDGE); + + // Mutation to create a new pledge + const [createPledge] = useMutation(CREATE_PlEDGE); + + // Effect to update the form state when the pledge prop changes (e.g., when editing a pledge) + useEffect(() => { + setFormState({ + pledgeUsers: pledge?.users ?? [], + pledgeAmount: pledge?.amount ?? 0, + pledgeCurrency: pledge?.currency ?? 'USD', + pledgeEndDate: new Date(pledge?.endDate ?? new Date()), + pledgeStartDate: new Date(pledge?.startDate ?? new Date()), + }); + }, [pledge]); + + // Destructuring the form state for easier access + const { + pledgeUsers, + pledgeAmount, + pledgeCurrency, + pledgeStartDate, + pledgeEndDate, + } = formState; + + // Query to get the user details based on the userId prop + const { data: userData } = useQuery(USER_DETAILS, { + variables: { + id: userId, + }, + }); + + // Effect to update the pledgers state when user data is fetched + useEffect(() => { + if (userData) { + setPledgers([ + { + _id: userData.user.user._id, + firstName: userData.user.user.firstName, + lastName: userData.user.user.lastName, + image: userData.user.user.image, + }, + ]); + } + }, [userData]); + + /** + * Handler function to update an existing pledge. + * It compares the current form state with the existing pledge and updates only the changed fields. + * + * @param e - The form submission event. + * @returns A promise that resolves when the pledge is successfully updated. + */ + /*istanbul ignore next*/ + const updatePledgeHandler = useCallback( + async (e: ChangeEvent): Promise => { + e.preventDefault(); + const startDate = dayjs(pledgeStartDate).format('YYYY-MM-DD'); + const endDate = dayjs(pledgeEndDate).format('YYYY-MM-DD'); + + const updatedFields: { + [key: string]: number | string | string[] | undefined; + } = {}; + // checks if there are changes to the pledge and adds them to the updatedFields object + if (pledgeAmount !== pledge?.amount) { + updatedFields.amount = pledgeAmount; + } + if (pledgeCurrency !== pledge?.currency) { + updatedFields.currency = pledgeCurrency; + } + if (startDate !== dayjs(pledge?.startDate).format('YYYY-MM-DD')) { + updatedFields.startDate = startDate; + } + if (endDate !== dayjs(pledge?.endDate).format('YYYY-MM-DD')) { + updatedFields.endDate = endDate; + } + if (pledgeUsers !== pledge?.users) { + updatedFields.users = pledgeUsers.map((user) => user._id); + } + try { + await updatePledge({ + variables: { + id: pledge?._id, + ...updatedFields, + }, + }); + toast.success(t('pledgeUpdated') as string); + refetchPledge(); + hide(); + } catch (error: unknown) { + toast.error((error as Error).message); + } + }, + [formState, pledge], + ); + + /** + * Handler function to create a new pledge. + * It collects the form data and sends a request to create a pledge with the specified details. + * + * @param e - The form submission event. + * @returns A promise that resolves when the pledge is successfully created. + */ + const createPledgeHandler = useCallback( + async (e: ChangeEvent): Promise => { + try { + e.preventDefault(); + await createPledge({ + variables: { + campaignId, + amount: pledgeAmount, + currency: pledgeCurrency, + startDate: dayjs(pledgeStartDate).format('YYYY-MM-DD'), + endDate: dayjs(pledgeEndDate).format('YYYY-MM-DD'), + userIds: pledgeUsers.map((user) => user._id), + }, + }); + + toast.success(t('pledgeCreated') as string); + refetchPledge(); + setFormState({ + pledgeUsers: [], + pledgeAmount: 0, + pledgeCurrency: 'USD', + pledgeEndDate: new Date(), + pledgeStartDate: new Date(), + }); + hide(); + } catch (error: unknown) { + /*istanbul ignore next*/ + toast.error((error as Error).message); + } + }, + [formState, campaignId], + ); + + return ( + + +

    + {t(mode === 'edit' ? 'editPledge' : 'createPledge')} +

    + +
    + +
    + {/* A Multi-select dropdown enables user to view participating pledgers */} + + option._id === value._id} + filterSelectedOptions={true} + getOptionLabel={(member: InterfacePledger): string => + `${member.firstName} ${member.lastName}` + } + onChange={ + /*istanbul ignore next*/ + (_, newPledgers): void => { + setFormState({ + ...formState, + pledgeUsers: newPledgers, + }); + } + } + renderInput={(params) => ( + + )} + /> + + + {/* Date Calendar Component to select start date of an event */} + { + if (date) { + setFormState({ + ...formState, + pledgeStartDate: date.toDate(), + pledgeEndDate: + pledgeEndDate && + /*istanbul ignore next*/ + (pledgeEndDate < date?.toDate() + ? date.toDate() + : pledgeEndDate), + }); + } + }} + minDate={dayjs(pledgeStartDate)} + maxDate={dayjs(endDate)} + /> + {/* Date Calendar Component to select end Date of an event */} + { + if (date) { + setFormState({ + ...formState, + pledgeEndDate: date.toDate(), + }); + } + }} + minDate={dayjs(pledgeStartDate)} + maxDate={dayjs(endDate)} + /> + + + {/* Dropdown to select the currency in which amount is to be pledged */} + + + {t('currency')} + + + + {/* Input field to enter amount to be pledged */} + + { + if (parseInt(e.target.value) > 0) { + setFormState({ + ...formState, + pledgeAmount: parseInt(e.target.value), + }); + } + }} + /> + + + {/* Button to submit the pledge form */} + +
    +
    +
    + ); +}; +export default PledgeModal; diff --git a/src/screens/UserPortal/Chat/Chat.module.css b/src/screens/UserPortal/Chat/Chat.module.css index 52edacdf64..5f9a672dea 100644 --- a/src/screens/UserPortal/Chat/Chat.module.css +++ b/src/screens/UserPortal/Chat/Chat.module.css @@ -1,63 +1,218 @@ +.containerHeight { + padding: 1rem 1.5rem 0 calc(300px); + height: 100vh; +} + +.expand { + padding-left: 4rem; + animation: moveLeft 0.9s ease-in-out; +} + +.contract { + padding-left: calc(300px); + animation: moveRight 0.5s ease-in-out; +} + +.collapseSidebarButton { + position: fixed; + height: 40px; + bottom: 0; + z-index: 9999; + width: 300px; + background-color: rgba(245, 245, 245, 0.7); + color: black; + border: none; + border-radius: 0px; +} + +.collapseSidebarButton:hover, +.opendrawer:hover { + opacity: 1; + color: black !important; +} + .containerHeight { height: 100vh; } .mainContainer { width: 50%; + margin-left: 20px; flex-grow: 3; - padding: 20px; max-height: 100%; overflow: auto; display: flex; flex-direction: row; + border: 1px solid rgb(220, 220, 220); + margin-top: 15px; + border-radius: 24px; + background-color: white; } .chatContainer { - flex-grow: 4; + flex-grow: 6; display: flex; flex-direction: column; - background-color: white; - border-top-right-radius: 10px; - border-bottom-right-radius: 10px; + margin: 20px; + border: 1px solid rgb(220, 220, 220); + border-radius: 24px; + overflow-y: scroll; + margin-left: 0px; +} + +.chatContainer::-webkit-scrollbar { + display: none; } .contactContainer { flex-grow: 1; display: flex; flex-direction: column; - background-color: white; - border-top-left-radius: 10px; - border-bottom-left-radius: 10px; -} - -.colorLight { - background-color: #f5f5f5; + width: 25%; + overflow-y: scroll; } .addChatContainer { - gap: 5px; - padding: 10px; + margin: 0 20px; + padding: 20px 0px 10px 0px; + border-bottom: 2px solid black; } -.contactListContainer { - flex-grow: 1; - padding: 15px 10px; +.contactCardContainer { + padding: 10px 15px; + display: flex; + flex-direction: column; + gap: 5px; } .chatHeadingContainer { padding: 10px; - color: white; - border-radius: 0px 10px 0px 0px; } .borderNone { border: none; } -.colorWhite { - color: white; +.accordion-button:focus { + box-shadow: none; +} + +.accordion-button:not(.collapsed) { + color: #212529; + background-color: white; +} + +.chatType { + --bs-accordion-btn-bg: white; + --bs-accordion-active-bg: white; + --bs-accordion-active-color: black; + --bs-accordion-btn-focus-box-shadow: none; + --bs-accordion-border-width: 0px; +} + +.chatType > button { + padding-bottom: 0; +} + +.createChat { + background-color: white; + border: none; +} + +.opendrawer { + position: fixed; + display: flex; + align-items: center; + justify-content: center; + top: 0; + left: 0; + width: 40px; + height: 100vh; + z-index: 9999; + background-color: rgba(245, 245, 245); + border: none; + border-radius: 0px; + margin-right: 20px; + color: black; +} + +.opendrawer:hover { + transition: background-color 0.5s ease; + background-color: var(--bs-primary); +} +.collapseSidebarButton:hover { + transition: background-color 0.5s ease; + background-color: var(--bs-primary); +} + +.customToggle { + padding: 0; + background: none; + border: none; + margin-right: 1rem; + --bs-btn-active-bg: none; +} +.customToggle svg { + color: black; +} + +.customToggle::after { + content: none; +} +.customToggle:hover, +.customToggle:focus, +.customToggle:active { + background: none; + border: none; +} +.customToggle svg { + color: black; +} + +@media (max-width: 1120px) { + .collapseSidebarButton { + width: calc(250px); + } +} + +@media (max-height: 650px) { + .collapseSidebarButton { + width: 250px; + height: 20px; + } + .opendrawer { + width: 30px; + } +} + +/* For tablets */ +@media (max-width: 820px) { + .containerHeight { + height: 100vh; + padding: 2rem; + } + + .contract, + .expand { + animation: none; + } + + .opendrawer { + width: 25px; + } + + .collapseSidebarButton { + width: 100%; + left: 0; + right: 0; + } +} + +.accordionBody { + height: calc(100vh / 2 - 2rem - 60px) !important; + overflow-y: scroll; } -.colorPrimary { - background: #31bb6b; +.accordionBody::-webkit-scrollbar { + display: none; } diff --git a/src/screens/UserPortal/Chat/Chat.test.tsx b/src/screens/UserPortal/Chat/Chat.test.tsx index b090266acf..d5e8049687 100644 --- a/src/screens/UserPortal/Chat/Chat.test.tsx +++ b/src/screens/UserPortal/Chat/Chat.test.tsx @@ -1,46 +1,803 @@ import React from 'react'; -import { act, render, screen } from '@testing-library/react'; +import { + act, + fireEvent, + render, + screen, + waitFor, +} from '@testing-library/react'; import { MockedProvider } from '@apollo/react-testing'; import { I18nextProvider } from 'react-i18next'; -import { ORGANIZATIONS_MEMBER_CONNECTION_LIST } from 'GraphQl/Queries/Queries'; +import { + USERS_CONNECTION_LIST, + USER_JOINED_ORGANIZATIONS, +} from 'GraphQl/Queries/Queries'; import { BrowserRouter } from 'react-router-dom'; import { Provider } from 'react-redux'; import { store } from 'state/store'; import i18nForTest from 'utils/i18nForTest'; -import { StaticMockLink } from 'utils/StaticMockLink'; import Chat from './Chat'; -import * as getOrganizationId from 'utils/getOrganizationId'; -import userEvent from '@testing-library/user-event'; +import useLocalStorage from 'utils/useLocalstorage'; +import { MESSAGE_SENT_TO_CHAT } from 'GraphQl/Mutations/OrganizationMutations'; +import { CHATS_LIST, CHAT_BY_ID } from 'GraphQl/Queries/PlugInQueries'; -const MOCKS = [ +const { setItem } = useLocalStorage(); + +const USER_JOINED_ORG_MOCK = [ + { + request: { + query: USER_JOINED_ORGANIZATIONS, + variables: { + id: '1', + }, + }, + result: { + data: { + users: [ + { + user: { + joinedOrganizations: [ + { + __typename: 'Organization', + _id: '6401ff65ce8e8406b8f07af2', + name: 'Any Organization', + image: '', + description: 'New Desc', + address: { + city: 'abc', + countryCode: '123', + postalCode: '456', + state: 'def', + dependentLocality: 'ghi', + line1: 'asdfg', + line2: 'dfghj', + sortingCode: '4567', + }, + createdAt: '1234567890', + userRegistrationRequired: true, + creator: { + __typename: 'User', + firstName: 'John', + lastName: 'Doe', + }, + members: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + admins: [ + { + _id: '45gj5678jk45678fvgbhnr4rtgh', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + membershipRequests: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + }, + ], + }, + }, + ], + }, + }, + }, + { + request: { + query: USER_JOINED_ORGANIZATIONS, + variables: { + id: '1', + }, + }, + result: { + data: { + users: [ + { + user: { + joinedOrganizations: [ + { + __typename: 'Organization', + _id: '6401ff65ce8e8406b8f07af2', + name: 'Any Organization', + image: '', + description: 'New Desc', + address: { + city: 'abc', + countryCode: '123', + postalCode: '456', + state: 'def', + dependentLocality: 'ghi', + line1: 'asdfg', + line2: 'dfghj', + sortingCode: '4567', + }, + createdAt: '1234567890', + userRegistrationRequired: true, + creator: { + __typename: 'User', + firstName: 'John', + lastName: 'Doe', + }, + members: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + admins: [ + { + _id: '45gj5678jk45678fvgbhnr4rtgh', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + membershipRequests: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + }, + ], + }, + }, + ], + }, + }, + }, + { + request: { + query: USER_JOINED_ORGANIZATIONS, + variables: { + id: '1', + }, + }, + result: { + data: { + users: [ + { + user: { + joinedOrganizations: [ + { + __typename: 'Organization', + _id: '6401ff65ce8e8406b8f07af2', + name: 'Any Organization', + image: '', + description: 'New Desc', + address: { + city: 'abc', + countryCode: '123', + postalCode: '456', + state: 'def', + dependentLocality: 'ghi', + line1: 'asdfg', + line2: 'dfghj', + sortingCode: '4567', + }, + createdAt: '1234567890', + userRegistrationRequired: true, + creator: { + __typename: 'User', + firstName: 'John', + lastName: 'Doe', + }, + members: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + admins: [ + { + _id: '45gj5678jk45678fvgbhnr4rtgh', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + membershipRequests: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + }, + ], + }, + }, + ], + }, + }, + }, + { + request: { + query: USER_JOINED_ORGANIZATIONS, + variables: { + id: null, + }, + }, + result: { + data: { + users: [ + { + user: { + joinedOrganizations: [ + { + __typename: 'Organization', + _id: '6401ff65ce8e8406b8f07af2', + name: 'Any Organization', + image: '', + description: 'New Desc', + address: { + city: 'abc', + countryCode: '123', + postalCode: '456', + state: 'def', + dependentLocality: 'ghi', + line1: 'asdfg', + line2: 'dfghj', + sortingCode: '4567', + }, + createdAt: '1234567890', + userRegistrationRequired: true, + creator: { + __typename: 'User', + firstName: 'John', + lastName: 'Doe', + }, + members: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + admins: [ + { + _id: '45gj5678jk45678fvgbhnr4rtgh', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + membershipRequests: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + }, + ], + }, + }, + ], + }, + }, + }, + { + request: { + query: USER_JOINED_ORGANIZATIONS, + variables: { + id: null, + }, + }, + result: { + data: { + users: [ + { + user: { + joinedOrganizations: [ + { + __typename: 'Organization', + _id: '6401ff65ce8e8406b8f07af2', + name: 'Any Organization', + image: '', + description: 'New Desc', + address: { + city: 'abc', + countryCode: '123', + postalCode: '456', + state: 'def', + dependentLocality: 'ghi', + line1: 'asdfg', + line2: 'dfghj', + sortingCode: '4567', + }, + createdAt: '1234567890', + userRegistrationRequired: true, + creator: { + __typename: 'User', + firstName: 'John', + lastName: 'Doe', + }, + members: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + admins: [ + { + _id: '45gj5678jk45678fvgbhnr4rtgh', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + membershipRequests: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + }, + ], + }, + }, + ], + }, + }, + }, + { + request: { + query: USER_JOINED_ORGANIZATIONS, + variables: { + id: null, + }, + }, + result: { + data: { + users: [ + { + user: { + joinedOrganizations: [ + { + __typename: 'Organization', + _id: '6401ff65ce8e8406b8f07af2', + name: 'Any Organization', + image: '', + description: 'New Desc', + address: { + city: 'abc', + countryCode: '123', + postalCode: '456', + state: 'def', + dependentLocality: 'ghi', + line1: 'asdfg', + line2: 'dfghj', + sortingCode: '4567', + }, + createdAt: '1234567890', + userRegistrationRequired: true, + creator: { + __typename: 'User', + firstName: 'John', + lastName: 'Doe', + }, + members: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + admins: [ + { + _id: '45gj5678jk45678fvgbhnr4rtgh', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + membershipRequests: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: '45ydeg2yet721rtgdu32ry', + }, + }, + ], + }, + ], + }, + }, + ], + }, + }, + }, +]; + +const UserConnectionListMock = [ { request: { - query: ORGANIZATIONS_MEMBER_CONNECTION_LIST, + query: USERS_CONNECTION_LIST, variables: { - orgId: '', firstName_contains: '', + lastName_contains: '', }, }, result: { data: { - organizationsMemberConnection: { - edges: [ - { - _id: '64001660a711c62d5b4076a2', - firstName: 'Noble', - lastName: 'Mittal', + users: [ + { + user: { + firstName: 'Deanne', + lastName: 'Marks', image: null, - email: 'noble1@gmail.com', - createdAt: '2023-03-02T03:22:08.101Z', + _id: '6589389d2caa9d8d69087487', + email: 'testuser8@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + organizationsBlockedBy: [], + joinedOrganizations: [ + { + _id: '6537904485008f171cf29924', + name: 'Unity Foundation', + image: null, + address: { + city: 'Queens', + countryCode: 'US', + dependentLocality: 'Some Dependent Locality', + line1: '123 Coffee Street', + line2: 'Apartment 501', + postalCode: '11427', + sortingCode: 'ABC-133', + state: 'NYC', + __typename: 'Address', + }, + createdAt: '2023-04-13T05:16:52.827Z', + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + __typename: 'Organization', + }, + { + _id: '6637904485008f171cf29924', + name: 'Unity Foundation', + image: null, + address: { + city: 'Staten Island', + countryCode: 'US', + dependentLocality: 'Some Dependent Locality', + line1: '123 church Street', + line2: 'Apartment 499', + postalCode: '10301', + sortingCode: 'ABC-122', + state: 'NYC', + __typename: 'Address', + }, + createdAt: '2023-04-13T05:16:52.827Z', + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + __typename: 'Organization', + }, + { + _id: '6737904485008f171cf29924', + name: 'Unity Foundation', + image: null, + address: { + city: 'Brooklyn', + countryCode: 'US', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Main Street', + line2: 'Apt 456', + postalCode: '10004', + sortingCode: 'ABC-789', + state: 'NY', + __typename: 'Address', + }, + createdAt: '2023-04-13T05:16:52.827Z', + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + __typename: 'Organization', + }, + { + _id: '6437904485008f171cf29924', + name: 'Unity Foundation', + image: null, + address: { + city: 'Bronx', + countryCode: 'US', + dependentLocality: 'Some Dependent Locality', + line1: '123 Random Street', + line2: 'Apartment 456', + postalCode: '10451', + sortingCode: 'ABC-123', + state: 'NYC', + __typename: 'Address', + }, + createdAt: '2023-04-13T05:16:52.827Z', + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + __typename: 'Organization', + }, + ], + __typename: 'User', + }, + appUserProfile: { + _id: '64378abd85308f171cf2993d', + adminFor: [], + isSuperAdmin: false, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + __typename: 'AppUserProfile', + }, + __typename: 'UserData', + }, + ], + }, + }, + }, + { + request: { + query: USERS_CONNECTION_LIST, + variables: { + firstName_contains: '', + lastName_contains: '', + }, + }, + result: { + data: { + users: { + user: [ + { + firstName: 'Disha', + lastName: 'Talreja', + image: 'img', + _id: '1', + email: 'disha@email.com', + createdAt: '', + appUserProfile: { + _id: '12', + isSuperAdmin: 'false', + createdOrganizations: { + _id: '345678', + }, + createdEvents: { + _id: '34567890', + }, + }, + organizationsBlockedBy: [], + joinedOrganizations: [], + }, + { + firstName: 'Disha', + lastName: 'Talreja', + image: 'img', + _id: '1', + email: 'disha@email.com', + createdAt: '', + appUserProfile: { + _id: '12', + isSuperAdmin: 'false', + createdOrganizations: { + _id: '345678', + }, + createdEvents: { + _id: '34567890', + }, + }, + organizationsBlockedBy: [], + joinedOrganizations: [], + }, + { + firstName: 'Disha', + lastName: 'Talreja', + image: 'img', + _id: '1', + email: 'disha@email.com', + createdAt: '', + appUserProfile: { + _id: '12', + isSuperAdmin: 'false', + createdOrganizations: { + _id: '345678', + }, + createdEvents: { + _id: '34567890', + }, + }, + organizationsBlockedBy: [], + joinedOrganizations: [], + }, + ], + }, + }, + }, + }, +]; + +const MESSAGE_SENT_TO_CHAT_MOCK = [ + { + request: { + query: MESSAGE_SENT_TO_CHAT, + variables: { + userId: null, + }, + }, + result: { + data: { + messageSentToChat: { + _id: '668ec1f1364e03ac47a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + type: 'STRING', + replyTo: null, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, + { + request: { + query: MESSAGE_SENT_TO_CHAT, + variables: { + userId: '2', + }, + }, + result: { + data: { + messageSentToGroupChat: { + _id: '668ec1f1df364e03ac47a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + replyTo: null, + type: 'STRING', + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, + { + request: { + query: MESSAGE_SENT_TO_CHAT, + variables: { + userId: '1', + }, + }, + result: { + data: { + messageSentToGroupChat: { + _id: '668ec1f13603ac4697a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + replyTo: null, + type: 'STRING', + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, +]; + +const CHAT_BY_ID_QUERY_MOCK = [ + { + request: { + query: CHAT_BY_ID, + variables: { + id: '1', + }, + }, + result: { + data: { + chatById: { + _id: '1', + createdAt: '2345678903456', + isGroup: false, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: null, + name: '', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + type: 'STRING', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, }, + ], + users: [ { - _id: '64001660a711c62d5b4076a3', - firstName: 'Noble', - lastName: 'Mittal', - image: 'mockImage', - email: 'noble@gmail.com', - createdAt: '2023-03-02T03:22:08.101Z', + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', }, ], }, @@ -49,23 +806,649 @@ const MOCKS = [ }, { request: { - query: ORGANIZATIONS_MEMBER_CONNECTION_LIST, + query: CHAT_BY_ID, variables: { - orgId: '', - firstName_contains: 'j', + id: '1', }, }, result: { data: { - organizationsMemberConnection: { - edges: [ + chatById: { + _id: '1', + isGroup: false, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: null, + name: '', + createdAt: '2345678903456', + messages: [ { - _id: '64001660a711c62d5b4076a2', - firstName: 'John', - lastName: 'Cena', + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + type: 'STRING', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + appUserProfile: { + _id: '64378abd85308f171cf2993d', + adminFor: [], + isSuperAdmin: false, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + __typename: 'AppUserProfile', + }, + __typename: 'UserData', + }, + ], + }, + }, + }, + }, + { + request: { + query: USERS_CONNECTION_LIST, + variables: { + firstName_contains: '', + lastName_contains: '', + }, + }, + result: { + data: { + users: { + user: [ + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + ], + }, + }, + }, + }, +]; + +const CHATS_LIST_MOCK = [ + { + request: { + query: CHATS_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844efc814dd40fgh03db811c4', + isGroup: true, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: { + _id: 'pw3ertyuiophgfre45678', + name: 'rtyu', + }, + createdAt: '2345678903456', + name: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + type: 'STRING', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + { + _id: '3', + firstName: 'Test', + lastName: 'User1', + email: 'test1@example.com', + image: '', + }, + { + _id: '4', + firstName: 'Test', + lastName: 'User2', + email: 'test2@example.com', + image: '', + }, + { + _id: '5', + firstName: 'Test', + lastName: 'User4', + email: 'test4@example.com', + image: '', + }, + ], + }, + { + _id: '65844efc814ddgh4003db811c4', + isGroup: true, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: { + _id: 'pw3ertyuiophgfre45678', + name: 'rtyu', + }, + createdAt: '2345678903456', + name: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + type: 'STRING', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + { + _id: '3', + firstName: 'Test', + lastName: 'User1', + email: 'test1@example.com', + image: '', + }, + { + _id: '4', + firstName: 'Test', + lastName: 'User2', + email: 'test2@example.com', + image: '', + }, + { + _id: '5', + firstName: 'Test', + lastName: 'User4', + email: 'test4@example.com', + image: '', + }, + ], + }, + ], + }, + }, + }, + { + request: { + query: CHATS_LIST, + variables: { + id: '', + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844ghjefc814dd4003db811c4', + isGroup: true, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: { + _id: 'pw3ertyuiophgfre45678', + name: 'rtyu', + }, + createdAt: '2345678903456', + name: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + type: 'STRING', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + { + _id: '3', + firstName: 'Test', + lastName: 'User1', + email: 'test1@example.com', + image: '', + }, + { + _id: '4', + firstName: 'Test', + lastName: 'User2', + email: 'test2@example.com', + image: '', + }, + { + _id: '5', + firstName: 'Test', + lastName: 'User4', + email: 'test4@example.com', + image: '', + }, + ], + }, + { + _id: 'ujhgtrdtyuiop', + isGroup: true, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: { + _id: 'pw3ertyuiophgfre45678', + name: 'rtyu', + }, + createdAt: '2345678903456', + name: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + type: 'STRING', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + { + _id: '3', + firstName: 'Test', + lastName: 'User1', + email: 'test1@example.com', + image: '', + }, + { + _id: '4', + firstName: 'Test', + lastName: 'User2', + email: 'test2@example.com', + image: '', + }, + { + _id: '5', + firstName: 'Test', + lastName: 'User4', + email: 'test4@example.com', + image: '', + }, + ], + }, + ], + }, + }, + }, + { + request: { + query: CHATS_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844efc814dhjmkdftyd4003db811c4', + isGroup: true, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', image: null, - email: 'john@gmail.com', - createdAt: '2023-03-02T03:22:08.101Z', + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: { + _id: 'pw3ertyuiophgfre45678', + name: 'rtyu', + }, + createdAt: '2345678903456', + name: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + type: 'STRING', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + { + _id: '3', + firstName: 'Test', + lastName: 'User1', + email: 'test1@example.com', + image: '', + }, + { + _id: '4', + firstName: 'Test', + lastName: 'User2', + email: 'test2@example.com', + image: '', + }, + { + _id: '5', + firstName: 'Test', + lastName: 'User4', + email: 'test4@example.com', + image: '', + }, + ], + }, + { + _id: '65844ewsedrffc814dd4003db811c4', + isGroup: true, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: { + _id: 'pw3ertyuiophgfre45678', + name: 'rtyu', + }, + createdAt: '2345678903456', + name: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + type: 'STRING', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + { + _id: '3', + firstName: 'Test', + lastName: 'User1', + email: 'test1@example.com', + image: '', + }, + { + _id: '4', + firstName: 'Test', + lastName: 'User2', + email: 'test2@example.com', + image: '', + }, + { + _id: '5', + firstName: 'Test', + lastName: 'User4', + email: 'test4@example.com', + image: '', + }, + ], + }, + ], + }, + }, + }, +]; + +const GROUP_CHAT_BY_ID_QUERY_MOCK = [ + { + request: { + query: CHAT_BY_ID, + variables: { + id: '', + }, + }, + result: { + data: { + chatById: { + _id: '65844efc814dd4003db811c4', + isGroup: true, + creator: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + email: 'testsuperadmin@example.com', + createdAt: '2023-04-13T04:53:17.742Z', + __typename: 'User', + }, + organization: { + _id: 'pw3ertyuiophgfre45678', + name: 'rtyu', + }, + createdAt: '2345678903456', + name: 'Test Group Chat', + messages: [ + { + _id: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + replyTo: null, + type: 'STRING', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + users: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + { + _id: '3', + firstName: 'Test', + lastName: 'User1', + email: 'test1@example.com', + image: '', + }, + { + _id: '4', + firstName: 'Test', + lastName: 'User2', + email: 'test2@example.com', + image: '', + }, + { + _id: '5', + firstName: 'Test', + lastName: 'User4', + email: 'test4@example.com', + image: '', }, ], }, @@ -74,7 +1457,10 @@ const MOCKS = [ }, ]; -const link = new StaticMockLink(MOCKS, true); +const resizeWindow = (width: number): void => { + window.innerWidth = width; + fireEvent(window, new Event('resize')); +}; async function wait(ms = 100): Promise { await act(() => { @@ -84,8 +1470,8 @@ async function wait(ms = 100): Promise { }); } -describe('Testing People Screen [User Portal]', () => { - jest.mock('utils/getOrganizationId'); +describe('Testing Chat Screen [User Portal]', () => { + window.HTMLElement.prototype.scrollIntoView = jest.fn(); Object.defineProperty(window, 'matchMedia', { writable: true, @@ -101,15 +1487,19 @@ describe('Testing People Screen [User Portal]', () => { })), }); - const getOrganizationIdSpy = jest - .spyOn(getOrganizationId, 'default') - .mockImplementation(() => { - return ''; - }); - test('Screen should be rendered properly', async () => { + const mock = [ + ...USER_JOINED_ORG_MOCK, + ...GROUP_CHAT_BY_ID_QUERY_MOCK, + ...MESSAGE_SENT_TO_CHAT_MOCK, + ...UserConnectionListMock, + ...CHAT_BY_ID_QUERY_MOCK, + ...CHATS_LIST_MOCK, + ...UserConnectionListMock, + ]; + render( - + @@ -119,16 +1509,23 @@ describe('Testing People Screen [User Portal]', () => { , ); - await wait(); - - expect(getOrganizationIdSpy).toHaveBeenCalled(); - expect(screen.queryAllByText('Noble Mittal')).not.toBe([]); }); test('User is able to select a contact', async () => { + const mock = [ + ...USER_JOINED_ORG_MOCK, + ...GROUP_CHAT_BY_ID_QUERY_MOCK, + ...MESSAGE_SENT_TO_CHAT_MOCK, + ...MESSAGE_SENT_TO_CHAT_MOCK, + ...UserConnectionListMock, + ...CHAT_BY_ID_QUERY_MOCK, + ...CHATS_LIST_MOCK, + ...UserConnectionListMock, + ]; + render( - + @@ -141,16 +1538,25 @@ describe('Testing People Screen [User Portal]', () => { await wait(); - userEvent.click(screen.getByText('noble1@gmail.com')); - await wait(); + expect(await screen.findByText('Messages')).toBeInTheDocument(); - expect(getOrganizationIdSpy).toHaveBeenCalled(); - expect(screen.queryAllByText('Noble Mittal')).not.toBe([]); + expect( + await screen.findByTestId('contactCardContainer'), + ).toBeInTheDocument(); }); - test('Search functionality works as expected by pressing enter key', async () => { + test('Test create new direct chat', async () => { + const mock = [ + ...USER_JOINED_ORG_MOCK, + ...GROUP_CHAT_BY_ID_QUERY_MOCK, + ...MESSAGE_SENT_TO_CHAT_MOCK, + ...MESSAGE_SENT_TO_CHAT_MOCK, + ...CHAT_BY_ID_QUERY_MOCK, + ...CHATS_LIST_MOCK, + ...UserConnectionListMock, + ]; render( - + @@ -163,17 +1569,35 @@ describe('Testing People Screen [User Portal]', () => { await wait(); - userEvent.type(screen.getByTestId('searchInput'), 'j{enter}'); - await wait(); + const dropdown = await screen.findByTestId('dropdown'); + expect(dropdown).toBeInTheDocument(); + fireEvent.click(dropdown); + const newDirectChatBtn = await screen.findByTestId('newDirectChat'); + expect(newDirectChatBtn).toBeInTheDocument(); + fireEvent.click(newDirectChatBtn); + + const closeButton = screen.getByRole('button', { name: /close/i }); + expect(closeButton).toBeInTheDocument(); - expect(getOrganizationIdSpy).toHaveBeenCalled(); - expect(screen.queryByText('John Cena')).toBeInTheDocument(); - expect(screen.queryByText('Noble Mittal')).not.toBeInTheDocument(); + const submitBtn = await screen.findByTestId('submitBtn'); + expect(submitBtn).toBeInTheDocument(); + + fireEvent.click(closeButton); }); - test('Search functionality works as expected by clicking search Btn', async () => { + test('Test create new group chat', async () => { + const mock = [ + ...USER_JOINED_ORG_MOCK, + ...GROUP_CHAT_BY_ID_QUERY_MOCK, + ...MESSAGE_SENT_TO_CHAT_MOCK, + ...UserConnectionListMock, + ...MESSAGE_SENT_TO_CHAT_MOCK, + ...CHAT_BY_ID_QUERY_MOCK, + ...CHATS_LIST_MOCK, + ...UserConnectionListMock, + ]; render( - + @@ -185,13 +1609,87 @@ describe('Testing People Screen [User Portal]', () => { ); await wait(); - const searchBtn = screen.getByTestId('searchBtn'); - userEvent.type(screen.getByTestId('searchInput'), 'j'); - userEvent.click(searchBtn); + + const dropdown = await screen.findByTestId('dropdown'); + expect(dropdown).toBeInTheDocument(); + fireEvent.click(dropdown); + + const newGroupChatBtn = await screen.findByTestId('newGroupChat'); + expect(newGroupChatBtn).toBeInTheDocument(); + + fireEvent.click(newGroupChatBtn); + const closeButton = screen.getByRole('button', { name: /close/i }); + expect(closeButton).toBeInTheDocument(); + + fireEvent.click(closeButton); + }); + + test('sidebar', async () => { + const mock = [ + ...USER_JOINED_ORG_MOCK, + ...GROUP_CHAT_BY_ID_QUERY_MOCK, + ...MESSAGE_SENT_TO_CHAT_MOCK, + ...UserConnectionListMock, + ...MESSAGE_SENT_TO_CHAT_MOCK, + ...CHAT_BY_ID_QUERY_MOCK, + ...CHATS_LIST_MOCK, + ...UserConnectionListMock, + ]; + setItem('userId', '1'); + + render( + + + + + + + + + , + ); + screen.debug(); + await waitFor(async () => { + const closeMenuBtn = await screen.findByTestId('closeMenu'); + expect(closeMenuBtn).toBeInTheDocument(); + if (closeMenuBtn) { + closeMenuBtn.click(); + } else { + throw new Error('Close menu button not found'); + } + }); + }); + + test('Testing sidebar when the screen size is less than or equal to 820px', async () => { + setItem('userId', '1'); + const mock = [ + ...USER_JOINED_ORG_MOCK, + ...GROUP_CHAT_BY_ID_QUERY_MOCK, + ...MESSAGE_SENT_TO_CHAT_MOCK, + ...UserConnectionListMock, + ...MESSAGE_SENT_TO_CHAT_MOCK, + ...CHAT_BY_ID_QUERY_MOCK, + ...CHATS_LIST_MOCK, + ...UserConnectionListMock, + ]; + resizeWindow(800); + render( + + + + + + + + + , + ); await wait(); + expect(screen.getByText('My Organizations')).toBeInTheDocument(); + expect(screen.getByText('Talawa User Portal')).toBeInTheDocument(); - expect(getOrganizationIdSpy).toHaveBeenCalled(); - expect(screen.queryByText('John Cena')).toBeInTheDocument(); - expect(screen.queryByText('Noble Mittal')).not.toBeInTheDocument(); + expect(await screen.findByTestId('openMenu')).toBeInTheDocument(); + fireEvent.click(screen.getByTestId('openMenu')); + expect(await screen.findByTestId('closeMenu')).toBeInTheDocument(); }); }); diff --git a/src/screens/UserPortal/Chat/Chat.tsx b/src/screens/UserPortal/Chat/Chat.tsx index ee6a6c04f1..441ce7d4ba 100644 --- a/src/screens/UserPortal/Chat/Chat.tsx +++ b/src/screens/UserPortal/Chat/Chat.tsx @@ -1,150 +1,249 @@ -import React from 'react'; -// import OrganizationNavbar from 'components/UserPortal/OrganizationNavbar/OrganizationNavbar'; -import { ORGANIZATIONS_MEMBER_CONNECTION_LIST } from 'GraphQl/Queries/Queries'; +import React, { useEffect, useState } from 'react'; import { useQuery } from '@apollo/client'; -import styles from './Chat.module.css'; -import getOrganizationId from 'utils/getOrganizationId'; import { useTranslation } from 'react-i18next'; -import { Form, InputGroup } from 'react-bootstrap'; -import { SearchOutlined } from '@mui/icons-material'; +import { Button, Dropdown } from 'react-bootstrap'; +import { SearchOutlined, Search } from '@mui/icons-material'; import HourglassBottomIcon from '@mui/icons-material/HourglassBottom'; import ContactCard from 'components/UserPortal/ContactCard/ContactCard'; import ChatRoom from 'components/UserPortal/ChatRoom/ChatRoom'; +import useLocalStorage from 'utils/useLocalstorage'; +import NewChat from 'assets/svgs/newChat.svg?react'; +import styles from './Chat.module.css'; +import UserSidebar from 'components/UserPortal/UserSidebar/UserSidebar'; +import { CHATS_LIST } from 'GraphQl/Queries/PlugInQueries'; +import CreateGroupChat from '../../../components/UserPortal/CreateGroupChat/CreateGroupChat'; +import CreateDirectChat from 'components/UserPortal/CreateDirectChat/CreateDirectChat'; interface InterfaceContactCardProps { id: string; - firstName: string; - lastName: string; - email: string; + title: string; image: string; selectedContact: string; setSelectedContact: React.Dispatch>; - setSelectedContactName: React.Dispatch>; + isGroup: boolean; } - -interface InterfaceChatRoomProps { - selectedContact: string; -} - +/** + * The `chat` component provides a user interface for interacting with contacts and chat rooms within an organization. + * It features a contact list with search functionality and displays the chat room for the selected contact. + * The component uses GraphQL to fetch and manage contact data, and React state to handle user interactions. + * + * ## Features: + * - **Search Contacts:** Allows users to search for contacts by their first name. + * - **Contact List:** Displays a list of contacts with their details and a profile image. + * - **Chat Room:** Shows the chat room for the selected contact. + * + * ## GraphQL Queries: + * - `ORGANIZATIONS_MEMBER_CONNECTION_LIST`: Fetches a list of members within an organization, with optional filtering based on the first name. + * + * ## Event Handlers: + * - `handleSearch`: Updates the filterName state and refetches the contact data based on the search query. + * - `handleSearchByEnter`: Handles search input when the Enter key is pressed. + * - `handleSearchByBtnClick`: Handles search input when the search button is clicked. + * + * ## Rendering: + * - Displays a search input field and a search button for filtering contacts. + * - Shows a list of contacts with their details and profile images. + * - Renders a chat room component for the selected contact. + * - Displays a loading indicator while contact data is being fetched. + * + * @returns The rendered `chat` component. + */ export default function chat(): JSX.Element { const { t } = useTranslation('translation', { - keyPrefix: 'userChat', + keyPrefix: 'chat', }); const { t: tCommon } = useTranslation('common'); - const organizationId = getOrganizationId(location.href); - const [selectedContact, setSelectedContact] = React.useState(''); - const [selectedContactName, setSelectedContactName] = React.useState(''); - const [contacts, setContacts] = React.useState([]); - const [filterName, setFilterName] = React.useState(''); + const [hideDrawer, setHideDrawer] = useState(null); + const [chats, setChats] = useState([]); + const [selectedContact, setSelectedContact] = useState(''); + const { getItem } = useLocalStorage(); + const userId = getItem('userId'); + + const handleResize = (): void => { + if (window.innerWidth <= 820) { + setHideDrawer(!hideDrawer); + } + }; + + useEffect(() => { + handleResize(); + window.addEventListener('resize', handleResize); + return () => { + window.removeEventListener('resize', handleResize); + }; + }, []); + + const [createDirectChatModalisOpen, setCreateDirectChatModalisOpen] = + useState(false); + + function openCreateDirectChatModal(): void { + setCreateDirectChatModalisOpen(true); + } + + const toggleCreateDirectChatModal = /* istanbul ignore next */ (): void => + setCreateDirectChatModalisOpen(!createDirectChatModalisOpen); + + const [createGroupChatModalisOpen, setCreateGroupChatModalisOpen] = + useState(false); - const chatRoomProps: InterfaceChatRoomProps = { - selectedContact, + function openCreateGroupChatModal(): void { + setCreateGroupChatModalisOpen(true); + } + + const toggleCreateGroupChatModal = /* istanbul ignore next */ (): void => { + setCreateGroupChatModalisOpen(!createGroupChatModalisOpen); }; const { - data: contactData, - loading: contactLoading, - refetch: contactRefetch, - } = useQuery(ORGANIZATIONS_MEMBER_CONNECTION_LIST, { + data: chatsListData, + loading: chatsListLoading, + refetch: chatsListRefetch, + } = useQuery(CHATS_LIST, { variables: { - orgId: organizationId, - firstName_contains: filterName, + id: userId, }, }); - const handleSearch = (value: string): void => { - setFilterName(value); - - contactRefetch({ - firstName_contains: value, - }); - }; - const handleSearchByEnter = ( - e: React.KeyboardEvent, - ): void => { - if (e.key === 'Enter') { - const { value } = e.currentTarget; - handleSearch(value); - } - }; - const handleSearchByBtnClick = (): void => { - const value = - (document.getElementById('searchChats') as HTMLInputElement)?.value || ''; - handleSearch(value); - }; - React.useEffect(() => { - if (contactData) { - setContacts(contactData.organizationsMemberConnection.edges); + if (chatsListData) { + setChats(chatsListData.chatsByUserId); } - }, [contactData]); + }, [chatsListData]); + + // const handleSearch = (value: string): void => { + // setFilterName(value); + + // contactRefetch(); + // }; + // const handleSearchByEnter = (e: any): void => { + // if (e.key === 'Enter') { + // const { value } = e.target; + // handleSearch(value); + // } + // }; + // const handleSearchByBtnClick = (): void => { + // const value = + // (document.getElementById('searchChats') as HTMLInputElement)?.value || ''; + // handleSearch(value); + // }; return ( <> - {/* */} + {hideDrawer ? ( + + ) : ( + + )} +
    -
    +
    -

    - {t('contacts')} -

    - - - Messages + + - - - + + + + + New Chat + + + New Group Chat + + + Starred Messages + + +
    - {contactLoading ? ( + {chatsListLoading ? (
    Loading...
    ) : ( - contacts.map( - (contact: InterfaceContactCardProps, index: number) => { - const cardProps: InterfaceContactCardProps = { - id: contact.id, - firstName: contact.firstName, - lastName: contact.lastName, - email: contact.email, - image: contact.image, - setSelectedContactName, - selectedContact, - setSelectedContact, - }; - return ; - }, - ) +
    + {!!chats.length && + chats.map((chat: any) => { + const cardProps: InterfaceContactCardProps = { + id: chat._id, + title: !chat.isGroup + ? chat.users[0]?._id === userId + ? `${chat.users[1]?.firstName} ${chat.users[1]?.lastName}` + : `${chat.users[0]?.firstName} ${chat.users[0]?.lastName}` + : chat.name, + image: chat.isGroup + ? userId + ? chat.users[1]?.image + : chat.users[0]?.image + : chat.image, + setSelectedContact, + selectedContact, + isGroup: chat.isGroup, + }; + return ( + + ); + })} +
    )}
    -
    -
    - {selectedContact ? selectedContactName : t('chat')} -
    - +
    +
    + {createGroupChatModalisOpen && ( + + )} + {createDirectChatModalisOpen && ( + + )} ); } diff --git a/src/screens/UserPortal/Donate/Donate.module.css b/src/screens/UserPortal/Donate/Donate.module.css index 4e21cb08d4..8f19db3ff8 100644 --- a/src/screens/UserPortal/Donate/Donate.module.css +++ b/src/screens/UserPortal/Donate/Donate.module.css @@ -1,25 +1,16 @@ -.containerHeight { - height: 100vh; -} - .mainContainer { width: 50%; flex-grow: 3; - padding: 1rem; - max-height: 100%; - overflow: auto; display: flex; flex-direction: column; background-color: #f2f7ff; } .inputContainer { - margin-top: 3rem; flex: 1; position: relative; } .input { - width: 70%; position: relative; box-shadow: 5px 5px 4px 0px #31bb6b1f; } diff --git a/src/screens/UserPortal/Donate/Donate.test.tsx b/src/screens/UserPortal/Donate/Donate.test.tsx index fc30ba7503..c4d435415e 100644 --- a/src/screens/UserPortal/Donate/Donate.test.tsx +++ b/src/screens/UserPortal/Donate/Donate.test.tsx @@ -1,5 +1,5 @@ -import React from 'react'; -import { act, render, screen } from '@testing-library/react'; +import React, { act } from 'react'; +import { render, screen } from '@testing-library/react'; import { MockedProvider } from '@apollo/react-testing'; import { I18nextProvider } from 'react-i18next'; @@ -16,6 +16,7 @@ import Donate from './Donate'; import userEvent from '@testing-library/user-event'; import useLocalStorage from 'utils/useLocalstorage'; import { DONATE_TO_ORGANIZATION } from 'GraphQl/Mutations/mutations'; +import { toast } from 'react-toastify'; const MOCKS = [ { @@ -136,6 +137,13 @@ jest.mock('react-router-dom', () => ({ useParams: () => ({ orgId: '' }), })); +jest.mock('react-toastify', () => ({ + toast: { + error: jest.fn(), + success: jest.fn(), + }, +})); + describe('Testing Donate Screen [User Portal]', () => { Object.defineProperty(window, 'matchMedia', { writable: true, @@ -280,4 +288,103 @@ describe('Testing Donate Screen [User Portal]', () => { userEvent.click(screen.getByTestId('donateBtn')); await wait(); }); + + test('displays error toast for donation amount below minimum', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.type(screen.getByTestId('donationAmount'), '0.5'); + userEvent.click(screen.getByTestId('donateBtn')); + + await wait(); + + expect(toast.error).toHaveBeenCalledWith( + 'Donation amount must be between 1 and 10000000.', + ); + }); + + test('displays error toast for donation amount above maximum', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.type(screen.getByTestId('donationAmount'), '10000001'); + userEvent.click(screen.getByTestId('donateBtn')); + + await wait(); + + expect(toast.error).toHaveBeenCalledWith( + 'Donation amount must be between 1 and 10000000.', + ); + }); + + test('displays error toast for empty donation amount', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('donateBtn')); + + await wait(); + + expect(toast.error).toHaveBeenCalledWith( + 'Please enter a numerical value for the donation amount.', + ); + }); + + test('displays error toast for invalid (non-numeric) donation amount', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.type(screen.getByTestId('donationAmount'), 'abc'); + userEvent.click(screen.getByTestId('donateBtn')); + + await wait(); + + expect(toast.error).toHaveBeenCalledWith( + 'Please enter a numerical value for the donation amount.', + ); + }); }); diff --git a/src/screens/UserPortal/Donate/Donate.tsx b/src/screens/UserPortal/Donate/Donate.tsx index 4e39c4e1be..c6e6d918d5 100644 --- a/src/screens/UserPortal/Donate/Donate.tsx +++ b/src/screens/UserPortal/Donate/Donate.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useEffect, useState } from 'react'; import { useParams } from 'react-router-dom'; import { Button, Dropdown, Form, InputGroup } from 'react-bootstrap'; import { toast } from 'react-toastify'; @@ -29,6 +29,39 @@ export interface InterfaceDonationCardProps { updatedAt: string; } +interface InterfaceDonation { + _id: string; + nameOfUser: string; + amount: string; + userId: string; + payPalId: string; + updatedAt: string; +} + +/** + * `donate` component allows users to make donations to an organization and view their previous donations. + * + * This component fetches donation-related data using GraphQL queries and allows users to make donations + * using a mutation. It supports currency selection, donation amount input, and displays a paginated list + * of previous donations. + * + * It includes: + * - An input field for searching donations. + * - A dropdown to select currency. + * - An input field for entering donation amount. + * - A button to submit the donation. + * - A list of previous donations displayed in a paginated format. + * - An organization sidebar for navigation. + * + * ### GraphQL Queries + * - `ORGANIZATION_DONATION_CONNECTION_LIST`: Fetches the list of donations for the organization. + * - `USER_ORGANIZATION_CONNECTION`: Fetches organization details. + * + * ### GraphQL Mutations + * - `DONATE_TO_ORGANIZATION`: Performs the donation action. + * + * @returns The rendered component. + */ export default function donate(): JSX.Element { const { t } = useTranslation('translation', { keyPrefix: 'donate', @@ -39,17 +72,19 @@ export default function donate(): JSX.Element { const userName = getItem('name'); const { orgId: organizationId } = useParams(); - const [amount, setAmount] = React.useState(''); - const [organizationDetails, setOrganizationDetails]: any = React.useState({}); - const [donations, setDonations] = React.useState([]); - const [selectedCurrency, setSelectedCurrency] = React.useState(0); - const [page, setPage] = React.useState(0); - const [rowsPerPage, setRowsPerPage] = React.useState(5); + const [amount, setAmount] = useState(''); + const [organizationDetails, setOrganizationDetails] = useState<{ + name: string; + }>({ name: '' }); + const [donations, setDonations] = useState([]); + const [selectedCurrency, setSelectedCurrency] = useState(0); + const [page, setPage] = useState(0); + const [rowsPerPage, setRowsPerPage] = useState(5); const currencies = ['USD', 'INR', 'EUR']; const { - data: data2, + data: donationData, loading, refetch, } = useQuery(ORGANIZATION_DONATION_CONNECTION_LIST, { @@ -62,10 +97,6 @@ export default function donate(): JSX.Element { const [donate] = useMutation(DONATE_TO_ORGANIZATION); - const navbarProps = { - currentPage: 'donate', - }; - /* istanbul ignore next */ const handleChangePage = ( _event: React.MouseEvent | null, @@ -84,19 +115,41 @@ export default function donate(): JSX.Element { setPage(0); }; - React.useEffect(() => { + useEffect(() => { if (data) { setOrganizationDetails(data.organizationsConnection[0]); } }, [data]); - React.useEffect(() => { - if (data2) { - setDonations(data2.getDonationByOrgIdConnection); + useEffect(() => { + if (donationData) { + setDonations(donationData.getDonationByOrgIdConnection); } - }, [data2]); + }, [donationData]); const donateToOrg = (): void => { + // check if the amount is non empty and is a number + if (amount === '' || Number.isNaN(Number(amount))) { + toast.error(t(`invalidAmount`)); + return; + } + + // check if the amount is non negative and within the range + const minDonation = 1; + const maxDonation = 10000000; + if ( + Number(amount) <= 0 || + Number(amount) < minDonation || + Number(amount) > maxDonation + ) { + toast.error( + t(`donationOutOfRange`, { min: minDonation, max: maxDonation }), + ); + return; + } + + const formattedAmount = Number(amount.trim()); + try { donate({ variables: { @@ -104,13 +157,13 @@ export default function donate(): JSX.Element { createDonationOrgId2: organizationId, payPalId: 'paypalId', nameOfUser: userName, - amount: Number(amount), + amount: formattedAmount, nameOfOrg: organizationDetails.name, }, }); refetch(); - toast.success(t(`success`)); - } catch (error: any) { + toast.success(t(`success`) as string); + } catch (error: unknown) { /* istanbul ignore next */ errorHandler(t, error); } @@ -118,9 +171,8 @@ export default function donate(): JSX.Element { return ( <> -
    -
    -

    {t(`donations`)}

    +
    +
    + + {t('donationAmountDescription')} +
    + + + ); + }, + }, + ]; + + return ( +
    +
    +
    + setSearchTerm(e.target.value)} + data-testid="searchPledges" + /> + +
    +
    + + + + + + {tCommon('sort')} + + + setSortBy('amount_ASC')} + data-testid="amount_ASC" + > + {t('lowestAmount')} + + setSortBy('amount_DESC')} + data-testid="amount_DESC" + > + {t('highestAmount')} + + setSortBy('endDate_DESC')} + data-testid="endDate_DESC" + > + {t('latestEndDate')} + + setSortBy('endDate_ASC')} + data-testid="endDate_ASC" + > + {t('earliestEndDate')} + + + +
    +
    + + row._id} + slots={{ + noRowsOverlay: () => ( + + {t('noPledges')} + + ), + }} + sx={dataGridStyle} + getRowClassName={() => `${styles.rowBackground}`} + autoHeight + rowHeight={65} + rows={pledges.map((pledge) => ({ + _id: pledge._id, + users: pledge.users, + startDate: pledge.startDate, + endDate: pledge.endDate, + amount: pledge.amount, + currency: pledge.currency, + campaign: pledge.campaign, + }))} + columns={columns} + isRowSelectable={() => false} + /> + + closeModal(ModalState.UPDATE)} + campaignId={pledge?.campaign ? pledge?.campaign._id : ''} + userId={userId} + pledge={pledge} + refetchPledge={refetchPledge} + endDate={pledge?.campaign ? pledge?.campaign.endDate : new Date()} + mode={'edit'} + /> + + closeModal(ModalState.DELETE)} + pledge={pledge} + refetchPledge={refetchPledge} + /> + + 4 ? styles.popupExtra : ''}`} + > + {extraUsers.map((user: InterfacePledger, index: number) => ( +
    + {user.image ? ( + pledger + ) : ( +
    + +
    + )} + + {user.firstName + ' ' + user.lastName} + +
    + ))} +
    +
    + ); +}; + +export default Pledges; diff --git a/src/screens/UserPortal/Pledges/PledgesMocks.ts b/src/screens/UserPortal/Pledges/PledgesMocks.ts new file mode 100644 index 0000000000..c7666987ff --- /dev/null +++ b/src/screens/UserPortal/Pledges/PledgesMocks.ts @@ -0,0 +1,596 @@ +import { DELETE_PLEDGE } from 'GraphQl/Mutations/PledgeMutation'; +import { USER_DETAILS } from 'GraphQl/Queries/Queries'; +import { USER_PLEDGES } from 'GraphQl/Queries/fundQueries'; + +const userDetailsQuery = { + request: { + query: USER_DETAILS, + variables: { + id: 'userId', + }, + }, + result: { + data: { + user: { + user: { + _id: 'userId', + joinedOrganizations: [ + { + _id: '6537904485008f171cf29924', + __typename: 'Organization', + }, + ], + firstName: 'Harve', + lastName: 'Lance', + email: 'testuser1@example.com', + image: null, + createdAt: '2023-04-13T04:53:17.742Z', + birthDate: null, + educationGrade: null, + employmentStatus: null, + gender: null, + maritalStatus: null, + phone: null, + address: { + line1: 'Line1', + countryCode: 'CountryCode', + city: 'CityName', + state: 'State', + __typename: 'Address', + }, + registeredEvents: [], + membershipRequests: [], + __typename: 'User', + }, + appUserProfile: { + _id: '67078abd85008f171cf2991d', + adminFor: [], + isSuperAdmin: false, + appLanguageCode: 'en', + pluginCreationAllowed: true, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + __typename: 'AppUserProfile', + }, + __typename: 'UserData', + }, + }, + }, +}; + +export const MOCKS = [ + { + request: { + query: USER_PLEDGES, + variables: { + userId: 'userId', + where: { + name_contains: '', + }, + orderBy: 'endDate_DESC', + }, + }, + result: { + data: { + getPledgesByUserId: [ + { + _id: 'pledgeId1', + amount: 700, + startDate: '2024-07-28', + endDate: '2024-08-13', + campaign: { + _id: 'campaignId1', + name: 'Hospital Campaign', + endDate: '2024-08-30', + __typename: 'FundraisingCampaign', + }, + currency: 'USD', + users: [ + { + _id: 'userId', + firstName: 'Harve', + lastName: 'Lance', + image: null, + __typename: 'User', + }, + { + _id: 'userId2', + firstName: 'Deanne', + lastName: 'Marks', + image: null, + __typename: 'User', + }, + { + _id: 'userId3', + firstName: 'Jeramy', + lastName: 'Garcia', + image: null, + __typename: 'User', + }, + { + _id: 'userId4', + firstName: 'Praise', + lastName: 'Norris', + image: null, + __typename: 'User', + }, + ], + __typename: 'FundraisingCampaignPledge', + }, + { + _id: 'pledgeId2', + amount: 100, + startDate: '2024-07-28', + endDate: '2024-08-13', + campaign: { + _id: 'campaignId2', + name: 'School Campaign', + endDate: '2024-08-30', + __typename: 'FundraisingCampaign', + }, + currency: 'USD', + users: [ + { + _id: 'userId5', + firstName: 'John', + lastName: 'Doe', + image: null, + __typename: 'User', + }, + { + _id: 'userId6', + firstName: 'Jane', + lastName: 'Doe', + image: null, + __typename: 'User', + }, + ], + __typename: 'FundraisingCampaignPledge', + }, + ], + }, + }, + }, + { + request: { + query: USER_PLEDGES, + variables: { + userId: 'userId', + where: { + firstName_contains: 'Harve', + }, + orderBy: 'endDate_DESC', + }, + }, + result: { + data: { + getPledgesByUserId: [ + { + _id: 'pledgeId1', + amount: 700, + startDate: '2024-07-28', + endDate: '2024-08-13', + campaign: { + _id: 'campaignId1', + name: 'Hospital Campaign', + endDate: '2024-08-30', + __typename: 'FundraisingCampaign', + }, + currency: 'USD', + users: [ + { + _id: 'userId', + firstName: 'Harve', + lastName: 'Lance', + image: null, + __typename: 'User', + }, + ], + __typename: 'FundraisingCampaignPledge', + }, + ], + }, + }, + }, + { + request: { + query: USER_PLEDGES, + variables: { + userId: 'userId', + where: { + name_contains: 'School', + }, + orderBy: 'endDate_DESC', + }, + }, + result: { + data: { + getPledgesByUserId: [ + { + _id: 'pledgeId2', + amount: 100, + startDate: '2024-07-28', + endDate: '2024-08-13', + campaign: { + _id: 'campaignId2', + name: 'School Campaign', + endDate: '2024-08-30', + __typename: 'FundraisingCampaign', + }, + currency: 'USD', + users: [ + { + _id: 'userId5', + firstName: 'John', + lastName: 'Doe', + image: null, + __typename: 'User', + }, + { + _id: 'userId6', + firstName: 'Jane', + lastName: 'Doe', + image: null, + __typename: 'User', + }, + ], + __typename: 'FundraisingCampaignPledge', + }, + ], + }, + }, + }, + { + request: { + query: USER_PLEDGES, + variables: { + userId: 'userId', + where: { + firstName_contains: '', + }, + orderBy: 'amount_ASC', + }, + }, + result: { + data: { + getPledgesByUserId: [ + { + _id: 'pledgeId2', + amount: 100, + startDate: '2024-07-28', + endDate: '2024-08-13', + campaign: { + _id: 'campaignId2', + name: 'School Campaign', + endDate: '2024-08-30', + __typename: 'FundraisingCampaign', + }, + currency: 'USD', + users: [ + { + _id: 'userId5', + firstName: 'John', + lastName: 'Doe', + image: null, + __typename: 'User', + }, + ], + __typename: 'FundraisingCampaignPledge', + }, + { + _id: 'pledgeId1', + amount: 700, + startDate: '2024-07-28', + endDate: '2024-08-13', + campaign: { + _id: 'campaignId1', + name: 'Hospital Campaign', + endDate: '2024-08-30', + __typename: 'FundraisingCampaign', + }, + currency: 'USD', + users: [ + { + _id: 'userId', + firstName: 'Harve', + lastName: 'Lance', + image: 'image-url', + __typename: 'User', + }, + ], + __typename: 'FundraisingCampaignPledge', + }, + ], + }, + }, + }, + { + request: { + query: USER_PLEDGES, + variables: { + userId: 'userId', + where: { + firstName_contains: '', + }, + orderBy: 'amount_DESC', + }, + }, + result: { + data: { + getPledgesByUserId: [ + { + _id: 'pledgeId1', + amount: 700, + startDate: '2024-07-28', + endDate: '2024-08-13', + campaign: { + _id: 'campaignId1', + name: 'Hospital Campaign', + endDate: '2024-08-30', + __typename: 'FundraisingCampaign', + }, + currency: 'USD', + users: [ + { + _id: 'userId', + firstName: 'Harve', + lastName: 'Lance', + image: 'image-url', + __typename: 'User', + }, + ], + __typename: 'FundraisingCampaignPledge', + }, + { + _id: 'pledgeId2', + amount: 100, + startDate: '2024-07-28', + endDate: '2024-08-13', + campaign: { + _id: 'campaignId2', + name: 'School Campaign', + endDate: '2024-08-30', + __typename: 'FundraisingCampaign', + }, + currency: 'USD', + users: [ + { + _id: 'userId5', + firstName: 'John', + lastName: 'Doe', + image: null, + __typename: 'User', + }, + ], + __typename: 'FundraisingCampaignPledge', + }, + ], + }, + }, + }, + { + request: { + query: USER_PLEDGES, + variables: { + userId: 'userId', + where: { + firstName_contains: '', + }, + orderBy: 'endDate_ASC', + }, + }, + result: { + data: { + getPledgesByUserId: [ + { + _id: 'pledgeId1', + amount: 700, + startDate: '2024-07-28', + endDate: '2024-08-13', + campaign: { + _id: 'campaignId1', + name: 'Hospital Campaign', + endDate: '2024-08-30', + __typename: 'FundraisingCampaign', + }, + currency: 'USD', + users: [ + { + _id: 'userId', + firstName: 'Harve', + lastName: 'Lance', + image: 'image-url', + __typename: 'User', + }, + ], + __typename: 'FundraisingCampaignPledge', + }, + { + _id: 'pledgeId2', + amount: 100, + startDate: '2024-07-28', + endDate: '2024-08-14', + campaign: { + _id: 'campaignId2', + name: 'School Campaign', + endDate: '2024-08-30', + __typename: 'FundraisingCampaign', + }, + currency: 'USD', + users: [ + { + _id: 'userId5', + firstName: 'John', + lastName: 'Doe', + image: null, + __typename: 'User', + }, + ], + __typename: 'FundraisingCampaignPledge', + }, + ], + }, + }, + }, + { + request: { + query: USER_PLEDGES, + variables: { + userId: 'userId', + where: { + firstName_contains: '', + }, + orderBy: 'endDate_DESC', + }, + }, + result: { + data: { + getPledgesByUserId: [ + { + _id: 'pledgeId2', + amount: 100, + startDate: '2024-07-28', + endDate: '2024-08-14', + campaign: { + _id: 'campaignId2', + name: 'School Campaign', + endDate: '2024-08-30', + __typename: 'FundraisingCampaign', + }, + currency: 'USD', + users: [ + { + _id: 'userId5', + firstName: 'John', + lastName: 'Doe', + image: null, + __typename: 'User', + }, + { + _id: 'userId6', + firstName: 'Jane', + lastName: 'Doe', + image: null, + __typename: 'User', + }, + { + _id: 'userId7', + firstName: 'John2', + lastName: 'Doe2', + image: 'image-url3', + __typename: 'User', + }, + { + _id: 'userId8', + firstName: 'Jane2', + lastName: 'Doe2', + image: null, + __typename: 'User', + }, + { + _id: 'userId9', + firstName: 'John3', + lastName: 'Doe3', + image: null, + __typename: 'User', + }, + { + _id: 'userId10', + firstName: 'Jane3', + lastName: 'Doe3', + image: null, + __typename: 'User', + }, + { + _id: 'userId11', + firstName: 'John4', + lastName: 'Doe4', + image: null, + __typename: 'User', + }, + ], + __typename: 'FundraisingCampaignPledge', + }, + { + _id: 'pledgeId1', + amount: 700, + startDate: '2024-07-28', + endDate: '2024-08-13', + campaign: { + _id: 'campaignId1', + name: 'Hospital Campaign', + endDate: '2024-08-30', + __typename: 'FundraisingCampaign', + }, + currency: 'USD', + users: [ + { + _id: 'userId', + firstName: 'Harve', + lastName: 'Lance', + image: 'image-url', + __typename: 'User', + }, + ], + __typename: 'FundraisingCampaignPledge', + }, + ], + }, + }, + }, + { + request: { + query: DELETE_PLEDGE, + variables: { + id: '1', + }, + }, + result: { + data: { + removeFundraisingCampaignPledge: { + _id: '1', + }, + }, + }, + }, + userDetailsQuery, +]; + +export const EMPTY_MOCKS = [ + { + request: { + query: USER_PLEDGES, + variables: { + userId: 'userId', + where: { + firstName_contains: '', + }, + orderBy: 'endDate_DESC', + }, + }, + result: { + data: { + getPledgesByUserId: [], + }, + }, + }, + userDetailsQuery, +]; + +export const USER_PLEDGES_ERROR = [ + { + request: { + query: USER_PLEDGES, + variables: { + userId: 'userId', + where: { + firstName_contains: '', + }, + orderBy: 'endDate_DESC', + }, + }, + error: new Error('Error fetching pledges'), + }, + userDetailsQuery, +]; diff --git a/src/screens/UserPortal/Posts/Posts.test.tsx b/src/screens/UserPortal/Posts/Posts.test.tsx index 4c49b7ba04..aa5f03fdcf 100644 --- a/src/screens/UserPortal/Posts/Posts.test.tsx +++ b/src/screens/UserPortal/Posts/Posts.test.tsx @@ -1,11 +1,11 @@ -import React from 'react'; +import React, { act } from 'react'; import { MockedProvider } from '@apollo/react-testing'; import type { RenderResult } from '@testing-library/react'; -import { act, render, screen, waitFor, within } from '@testing-library/react'; +import { render, screen, waitFor, within } from '@testing-library/react'; import { I18nextProvider } from 'react-i18next'; import userEvent from '@testing-library/user-event'; import { - ADVERTISEMENTS_GET, + ORGANIZATION_ADVERTISEMENT_LIST, ORGANIZATION_POST_LIST, } from 'GraphQl/Queries/Queries'; import { Provider } from 'react-redux'; @@ -15,6 +15,7 @@ import { StaticMockLink } from 'utils/StaticMockLink'; import i18nForTest from 'utils/i18nForTest'; import Home from './Posts'; import useLocalStorage from 'utils/useLocalstorage'; +import { DELETE_POST_MUTATION } from 'GraphQl/Mutations/mutations'; const { setItem } = useLocalStorage(); @@ -137,67 +138,94 @@ const MOCKS = [ }, { request: { - query: ADVERTISEMENTS_GET, - variables: {}, + query: ORGANIZATION_ADVERTISEMENT_LIST, + variables: { id: 'orgId', first: 6 }, }, result: { data: { - advertisementsConnection: { - edges: [ - { - node: { - _id: '1234', - name: 'Ad 1', - type: 'Type 1', - organization: { - _id: 'orgId', + organizations: [ + { + _id: 'orgId', + advertisements: { + edges: [ + { + node: { + _id: '1234', + name: 'Ad 1', + type: 'Type 1', + organization: { + _id: 'orgId', + }, + mediaUrl: 'Link 1', + endDate: '2024-12-31', + startDate: '2022-01-01', + }, + cursor: '1234', }, - mediaUrl: 'Link 1', - endDate: '2024-12-31', - startDate: '2022-01-01', - }, - }, - { - node: { - _id: '2345', - name: 'Ad 2', - type: 'Type 1', - organization: { - _id: 'orgId', + { + node: { + _id: '2345', + name: 'Ad 2', + type: 'Type 1', + organization: { + _id: 'orgId', + }, + mediaUrl: 'Link 2', + endDate: '2024-09-31', + startDate: '2023-04-01', + }, + cursor: '1234', }, - mediaUrl: 'Link 2', - endDate: '2024-09-31', - startDate: '2023-04-01', - }, - }, - { - node: { - _id: '3456', - name: 'name3', - type: 'Type 2', - organization: { - _id: 'orgId', + { + node: { + _id: '3456', + name: 'name3', + type: 'Type 2', + organization: { + _id: 'orgId', + }, + mediaUrl: 'link3', + startDate: '2023-01-30', + endDate: '2023-12-31', + }, + cursor: '1234', }, - mediaUrl: 'link3', - startDate: '2023-01-30', - endDate: '2023-12-31', - }, - }, - { - node: { - _id: '4567', - name: 'name4', - type: 'Type 2', - organization: { - _id: 'orgId1', + { + node: { + _id: '4567', + name: 'name4', + type: 'Type 2', + organization: { + _id: 'orgId1', + }, + mediaUrl: 'link4', + startDate: '2023-01-30', + endDate: '2023-12-01', + }, + cursor: '1234', }, - mediaUrl: 'link4', - startDate: '2023-01-30', - endDate: '2023-12-01', + ], + pageInfo: { + startCursor: '6411e53835d7ba2344a78e21', + endCursor: '6411e54835d7ba2344a78e31', + hasNextPage: false, + hasPreviousPage: false, }, + totalCount: 2, }, - ], - }, + }, + ], + }, + }, + }, + { + request: { + query: DELETE_POST_MUTATION, + variables: { id: '6411e54835d7ba2344a78e29' }, + }, + result: { + data: { + removePost: { _id: '6411e54835d7ba2344a78e29' }, }, }, }, @@ -334,10 +362,11 @@ describe('Testing Home Screen: User Portal', () => { test('Checking if refetch works after deleting this post', async () => { setItem('userId', '640d98d9eb6a743d75341067'); renderHomeScreen(); - await wait(); - - userEvent.click(screen.getAllByTestId('dropdown')[1]); - userEvent.click(screen.getByTestId('deletePost')); + expect(screen.queryAllByTestId('dropdown')).not.toBeNull(); + const dropdowns = await screen.findAllByTestId('dropdown'); + userEvent.click(dropdowns[1]); + const deleteButton = await screen.findByTestId('deletePost'); + userEvent.click(deleteButton); }); }); @@ -364,11 +393,7 @@ describe('HomeScreen with invalid orgId', () => { , ); - - // Wait for the navigation to occur - await waitFor(() => { - const homeEl = screen.getByTestId('homeEl'); - expect(homeEl).toBeInTheDocument(); - }); + const homeEl = await screen.findByTestId('homeEl'); + expect(homeEl).toBeInTheDocument(); }); }); diff --git a/src/screens/UserPortal/Posts/Posts.tsx b/src/screens/UserPortal/Posts/Posts.tsx index aaa5345f1c..256bb5f52f 100644 --- a/src/screens/UserPortal/Posts/Posts.tsx +++ b/src/screens/UserPortal/Posts/Posts.tsx @@ -1,16 +1,15 @@ import { useQuery } from '@apollo/client'; import HourglassBottomIcon from '@mui/icons-material/HourglassBottom'; import SendIcon from '@mui/icons-material/Send'; -import ChevronRightIcon from '@mui/icons-material/ChevronRight'; -import ChevronLeftIcon from '@mui/icons-material/ChevronLeft'; import { - ADVERTISEMENTS_GET, + ORGANIZATION_ADVERTISEMENT_LIST, ORGANIZATION_POST_LIST, USER_DETAILS, } from 'GraphQl/Queries/Queries'; import PostCard from 'components/UserPortal/PostCard/PostCard'; import type { InterfacePostCard, + InterfaceQueryOrganizationAdvertisementListItem, InterfaceQueryUserListItem, } from 'utils/interfaces'; import PromotedPost from 'components/UserPortal/PromotedPost/PromotedPost'; @@ -23,7 +22,36 @@ import { Navigate, useParams } from 'react-router-dom'; import useLocalStorage from 'utils/useLocalstorage'; import styles from './Posts.module.css'; import convertToBase64 from 'utils/convertToBase64'; +import Carousel from 'react-multi-carousel'; +import 'react-multi-carousel/lib/styles.css'; + +const responsive = { + superLargeDesktop: { + breakpoint: { max: 4000, min: 3000 }, + items: 5, + }, + desktop: { + breakpoint: { max: 3000, min: 1024 }, + items: 3, + }, + tablet: { + breakpoint: { max: 1024, min: 600 }, + items: 2, + }, + mobile: { + breakpoint: { max: 600, min: 0 }, + items: 1, + }, +}; +type Ad = { + _id: string; + name: string; + type: 'BANNER' | 'MENU' | 'POPUP'; + mediaUrl: string; + endDate: string; // Assuming it's a string in the format 'yyyy-MM-dd' + startDate: string; // Assuming it's a string in the format 'yyyy-MM-dd' +}; interface InterfaceAdContent { _id: string; name: string; @@ -45,10 +73,6 @@ type AdvertisementsConnection = { }[]; }; -interface InterfaceAdConnection { - advertisementsConnection?: AdvertisementsConnection; -} - type InterfacePostComments = { creator: { _id: string; @@ -95,26 +119,49 @@ type InterfacePostNode = { likes: InterfacePostLikes; }; +/** + * `home` component displays the main feed for a user, including posts, promoted content, and options to create a new post. + * + * It utilizes Apollo Client for fetching and managing data through GraphQL queries. The component fetches and displays posts from an organization, promoted advertisements, and handles user interactions for creating new posts. It also manages state for displaying modal dialogs and handling file uploads for new posts. + * + * @returns JSX.Element - The rendered `home` component. + */ export default function home(): JSX.Element { + // Translation hook for localized text const { t } = useTranslation('translation', { keyPrefix: 'home' }); const { t: tCommon } = useTranslation('common'); + + // Custom hook for accessing local storage const { getItem } = useLocalStorage(); const [posts, setPosts] = useState([]); const [pinnedPosts, setPinnedPosts] = useState([]); - const [adContent, setAdContent] = useState({}); - const [filteredAd, setFilteredAd] = useState([]); + const [showModal, setShowModal] = useState(false); const [postImg, setPostImg] = useState(''); + + // Fetching the organization ID from URL parameters const { orgId } = useParams(); + // Redirect to user page if organization ID is not available if (!orgId) { return ; } - const navbarProps = { - currentPage: 'home', - }; - const { data: promotedPostsData } = useQuery(ADVERTISEMENTS_GET); + // Query hooks for fetching posts, advertisements, and user details + const { + data: promotedPostsData, + }: { + data?: { + organizations: InterfaceQueryOrganizationAdvertisementListItem[]; + }; + refetch: () => void; + } = useQuery(ORGANIZATION_ADVERTISEMENT_LIST, { + variables: { + id: orgId, + first: 6, + }, + }); + const { data, refetch, @@ -122,6 +169,8 @@ export default function home(): JSX.Element { } = useQuery(ORGANIZATION_POST_LIST, { variables: { id: orgId, first: 10 }, }); + + const [adContent, setAdContent] = useState([]); const userId: string | null = getItem('userId'); const { data: userData } = useQuery(USER_DETAILS, { @@ -130,22 +179,25 @@ export default function home(): JSX.Element { const user: InterfaceQueryUserListItem | undefined = userData?.user; + // Effect hook to update posts state when data changes useEffect(() => { if (data) { setPosts(data.organizations[0].posts.edges); } }, [data]); + // Effect hook to update advertisements state when data changes useEffect(() => { - if (promotedPostsData) { - setAdContent(promotedPostsData); + if (promotedPostsData && promotedPostsData.organizations) { + const ads: Ad[] = + promotedPostsData.organizations[0].advertisements?.edges.map( + (edge) => edge.node, + ) || []; + + setAdContent(ads); } }, [promotedPostsData]); - useEffect(() => { - setFilteredAd(filterAdContent(adContent, orgId)); - }, [adContent]); - useEffect(() => { setPinnedPosts( posts.filter(({ node }: { node: InterfacePostNode }) => { @@ -154,34 +206,12 @@ export default function home(): JSX.Element { ); }, [posts]); - const filterAdContent = ( - data: { - advertisementsConnection?: { - edges: { - node: InterfaceAdContent; - }[]; - }; - }, - currentOrgId: string, - currentDate: Date = new Date(), - ): InterfaceAdContent[] => { - const { advertisementsConnection } = data; - - if (advertisementsConnection && advertisementsConnection.edges) { - const { edges } = advertisementsConnection; - - return edges - .map((edge) => edge.node) - .filter( - (ad: InterfaceAdContent) => - ad.organization._id === currentOrgId && - new Date(ad.endDate) > currentDate, - ); - } - - return []; - }; - + /** + * Converts a post node into props for the `PostCard` component. + * + * @param node - The post node to convert. + * @returns The props for the `PostCard` component. + */ const getCardProps = (node: InterfacePostNode): InterfacePostCard => { const { creator, @@ -263,10 +293,16 @@ export default function home(): JSX.Element { return cardProps; }; + /** + * Opens the post creation modal. + */ const handlePostButtonClick = (): void => { setShowModal(true); }; + /** + * Closes the post creation modal. + */ const handleModalClose = (): void => { setShowModal(false); }; @@ -321,21 +357,18 @@ export default function home(): JSX.Element { >

    {t('feed')}

    {pinnedPosts.length > 0 && ( -
    -

    {t(`pinnedPosts`)}

    -
    - {pinnedPosts.map(({ node }: { node: InterfacePostNode }) => { - const cardProps = getCardProps(node); - return ; - })} -
    -
    + + {pinnedPosts.map(({ node }: { node: InterfacePostNode }) => { + const cardProps = getCardProps(node); + return ; + })} + )}
    - {filteredAd.length > 0 && ( + {adContent.length > 0 && (
    - {filteredAd.map((post: InterfaceAdContent) => ( + {adContent.map((post: Ad) => ( { }; async function wait(ms = 100): Promise { - await act(() => { + await act(async () => { return new Promise((resolve) => { setTimeout(resolve, ms); }); @@ -124,32 +154,37 @@ async function wait(ms = 100): Promise { } describe('Testing Settings Screen [User Portal]', () => { - Object.defineProperty(window, 'matchMedia', { - writable: true, - value: jest.fn().mockImplementation((query) => ({ - matches: false, - media: query, - onchange: null, - addListener: jest.fn(), // Deprecated - removeListener: jest.fn(), // Deprecated - addEventListener: jest.fn(), - removeEventListener: jest.fn(), - dispatchEvent: jest.fn(), - })), + // Mock implementation of matchMedia + beforeAll(() => { + Object.defineProperty(window, 'matchMedia', { + writable: true, + value: jest.fn().mockImplementation((query) => ({ + matches: false, + media: query, + onchange: null, + addListener: jest.fn(), // Deprecated + removeListener: jest.fn(), // Deprecated + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn(), + })), + }); }); test('Screen should be rendered properly', async () => { - render( - - - - - - - - - , - ); + await act(async () => { + render( + + + + + + + + + , + ); + }); await wait(); @@ -157,17 +192,19 @@ describe('Testing Settings Screen [User Portal]', () => { }); test('input works properly', async () => { - render( - - - - - - - - - , - ); + await act(async () => { + render( + + + + + + + + + , + ); + }); await wait(); @@ -212,17 +249,19 @@ describe('Testing Settings Screen [User Portal]', () => { }); test('resetChangesBtn works properly', async () => { - render( - - - - - - - - - , - ); + await act(async () => { + render( + + + + + + + + + , + ); + }); await wait(); userEvent.type(screen.getByTestId('inputAddress'), 'random'); @@ -243,17 +282,19 @@ describe('Testing Settings Screen [User Portal]', () => { }); test('resetChangesBtn works properly when the details are empty', async () => { - render( - - - - - - - - - , - ); + await act(async () => { + render( + + + + + + + + + , + ); + }); await wait(); userEvent.type(screen.getByTestId('inputAddress'), 'random'); @@ -274,99 +315,65 @@ describe('Testing Settings Screen [User Portal]', () => { }); test('sidebar', async () => { - render( - - - - - - - - - , - ); + await act(async () => { + render( + + + + + + + + + , + ); + }); await wait(); const closeMenubtn = screen.getByTestId('closeMenu'); expect(closeMenubtn).toBeInTheDocument(); - closeMenubtn.click(); + act(() => closeMenubtn.click()); const openMenuBtn = screen.getByTestId('openMenu'); expect(openMenuBtn).toBeInTheDocument(); - openMenuBtn.click(); + act(() => openMenuBtn.click()); }); test('Testing sidebar when the screen size is less than or equal to 820px', async () => { resizeWindow(800); - render( - - - - - - - - - , - ); - await wait(); - expect(screen.getByText('My Organizations')).toBeInTheDocument(); - expect(screen.getByText('Talawa User Portal')).toBeInTheDocument(); - - const settingsBtn = screen.getByTestId('settingsBtn'); - - settingsBtn.click(); - }); - - test('updateUserDetails Mutation is triggered on button click', async () => { - render( - - - - - - - - - , - ); - - await wait(); - - userEvent.type(screen.getByTestId('inputFirstName'), 'Noble'); - await wait(); - - userEvent.type(screen.getByTestId('inputLastName'), 'Mittal'); - await wait(); - - userEvent.selectOptions(screen.getByTestId('inputGender'), 'OTHER'); - await wait(); - - userEvent.type(screen.getByTestId('inputPhoneNumber'), '+174567890'); - await wait(); - - fireEvent.change(screen.getByLabelText('Birth Date'), { - target: { value: '2024-03-01' }, + await act(async () => { + render( + + + + + + + + + , + ); }); - await wait(); - userEvent.selectOptions(screen.getByTestId('inputGrade'), 'Graduate'); await wait(); - userEvent.selectOptions(screen.getByTestId('inputEmpStatus'), 'Unemployed'); - await wait(); + screen.debug(); - userEvent.selectOptions(screen.getByTestId('inputMaritalStatus'), 'Single'); - await wait(); + const openMenuBtn = screen.queryByTestId('openMenu'); + console.log('Open Menu Button:', openMenuBtn); + expect(openMenuBtn).toBeInTheDocument(); - userEvent.type(screen.getByTestId('inputAddress'), 'random'); - await wait(); + if (openMenuBtn) { + act(() => openMenuBtn.click()); + } - userEvent.type(screen.getByTestId('inputState'), 'random'); - await wait(); + const closeMenuBtn = screen.queryByTestId('closeMenu'); + console.log('Close Menu Button:', closeMenuBtn); + expect(closeMenuBtn).toBeInTheDocument(); - userEvent.click(screen.getByTestId('updateUserBtn')); - await wait(); + if (closeMenuBtn) { + act(() => closeMenuBtn.click()); + } }); test('renders events attended card correctly', async () => { diff --git a/src/screens/UserPortal/Settings/Settings.tsx b/src/screens/UserPortal/Settings/Settings.tsx index 054f3a317d..e46d4f1127 100644 --- a/src/screens/UserPortal/Settings/Settings.tsx +++ b/src/screens/UserPortal/Settings/Settings.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; import styles from './Settings.module.css'; import { Button, Card, Col, Form, Row } from 'react-bootstrap'; @@ -25,6 +25,12 @@ import EventsAttendedByMember from 'components/MemberDetail/EventsAttendedByMemb import CardItemLoading from 'components/OrganizationDashCards/CardItemLoading'; import type { InterfaceEvent } from 'components/EventManagement/EventAttendance/InterfaceEvents'; +/** + * The Settings component allows users to view and update their profile settings. + * It includes functionality to handle image uploads, reset changes, and save updated user details. + * + * @returns The Settings component. + */ export default function settings(): JSX.Element { const { t } = useTranslation('translation', { keyPrefix: 'settings', @@ -33,6 +39,10 @@ export default function settings(): JSX.Element { const [isUpdated, setisUpdated] = useState(null); const [hideDrawer, setHideDrawer] = useState(null); + /** + * Handler to adjust sidebar visibility based on window width. + * This function is invoked on window resize and when the component mounts. + */ const handleResize = (): void => { if (window.innerWidth <= 820) { setHideDrawer(!hideDrawer); @@ -48,12 +58,12 @@ export default function settings(): JSX.Element { }, []); const { setItem } = useLocalStorage(); - const { data } = useQuery(CHECK_AUTH, { fetchPolicy: 'network-only' }); const [updateUserDetails] = useMutation(UPDATE_USER_MUTATION); const [userDetails, setUserDetails] = React.useState({ firstName: '', lastName: '', + createdAt: '', gender: '', email: '', phoneNumber: '', @@ -67,9 +77,21 @@ export default function settings(): JSX.Element { image: '', eventsAttended: [] as InterfaceEvent[], }); - console.log(userDetails); + + /** + * Ref to store the original image URL for comparison during updates. + */ const originalImageState = React.useRef(''); + /** + * Ref to access the file input element for image uploads. + */ const fileInputRef = React.useRef(null); + + /** + * Handles the update of user details. + * This function sends a mutation request to update the user details + * and reloads the page on success. + */ const handleUpdateUserDetails = async (): Promise => { try { let updatedUserDetails = { ...userDetails }; @@ -81,11 +103,12 @@ export default function settings(): JSX.Element { }); /* istanbul ignore next */ if (data) { - toast.success('Your details have been updated.'); + toast.success( + tCommon('updatedSuccessfully', { item: 'Profile' }) as string, + ); setTimeout(() => { window.location.reload(); }, 500); - const userFullName = `${userDetails.firstName} ${userDetails.lastName}`; setItem('name', userFullName); } @@ -94,6 +117,12 @@ export default function settings(): JSX.Element { } }; + /** + * Handles the change of a specific field in the user details state. + * + * @param fieldName - The name of the field to be updated. + * @param value - The new value for the field. + */ const handleFieldChange = (fieldName: string, value: string): void => { setisUpdated(true); setUserDetails((prevState) => ({ @@ -102,6 +131,9 @@ export default function settings(): JSX.Element { })); }; + /** + * Triggers the file input click event to open the file picker dialog. + */ const handleImageUpload = (): void => { setisUpdated(true); if (fileInputRef.current) { @@ -109,6 +141,9 @@ export default function settings(): JSX.Element { } }; + /** + * Resets the user details to the values fetched from the server. + */ const handleResetChanges = (): void => { setisUpdated(!isUpdated); /* istanbul ignore next */ @@ -116,6 +151,7 @@ export default function settings(): JSX.Element { const { firstName, lastName, + createdAt, gender, phone, birthDate, @@ -129,6 +165,7 @@ export default function settings(): JSX.Element { ...userDetails, firstName: firstName || '', lastName: lastName || '', + createdAt: createdAt || '', gender: gender || '', phoneNumber: phone?.mobile || '', birthDate: birthDate || '', @@ -142,12 +179,13 @@ export default function settings(): JSX.Element { } }; - React.useEffect(() => { + useEffect(() => { /* istanbul ignore next */ if (data) { const { firstName, lastName, + createdAt, gender, email, phone, @@ -163,6 +201,7 @@ export default function settings(): JSX.Element { setUserDetails({ firstName, lastName, + createdAt, gender, email, phoneNumber: phone?.mobile || '', @@ -214,7 +253,10 @@ export default function settings(): JSX.Element { }`} >
    -
    +
    +
    +

    {tCommon('settings')}

    +

    {tCommon('settings')}

    diff --git a/src/screens/UserPortal/UserScreen/UserScreen.test.tsx b/src/screens/UserPortal/UserScreen/UserScreen.test.tsx index 3600e7a991..96ee9767f2 100644 --- a/src/screens/UserPortal/UserScreen/UserScreen.test.tsx +++ b/src/screens/UserPortal/UserScreen/UserScreen.test.tsx @@ -12,9 +12,12 @@ import { ORGANIZATIONS_LIST } from 'GraphQl/Queries/Queries'; import { StaticMockLink } from 'utils/StaticMockLink'; let mockID: string | undefined = '123'; +let mockLocation: string | undefined = '/user/organization/123'; + jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), useParams: () => ({ orgId: mockID }), + useLocation: () => ({ pathname: mockLocation }), })); const MOCKS = [ @@ -70,6 +73,42 @@ const clickToggleMenuBtn = (toggleButton: HTMLElement): void => { }; describe('Testing LeftDrawer in OrganizationScreen', () => { + test('renders the correct title based on the titleKey for posts', () => { + render( + + + + + + + + + , + ); + + const titleElement = screen.getByRole('heading', { level: 1 }); + expect(titleElement).toHaveTextContent(''); + }); + + test('renders the correct title based on the titleKey', () => { + mockLocation = '/user/people/123'; + + render( + + + + + + + + + , + ); + + const titleElement = screen.getByRole('heading', { level: 1 }); + expect(titleElement).toHaveTextContent('People'); + }); + test('Testing LeftDrawer in page functionality', async () => { render( @@ -89,8 +128,8 @@ describe('Testing LeftDrawer in OrganizationScreen', () => { resizeWindow(800); clickToggleMenuBtn(toggleButton); expect(icon).toHaveClass('fa fa-angle-double-left'); - // Resize window back to a larger width + // Resize window back to a larger width resizeWindow(1000); clickToggleMenuBtn(toggleButton); expect(icon).toHaveClass('fa fa-angle-double-right'); diff --git a/src/screens/UserPortal/UserScreen/UserScreen.tsx b/src/screens/UserPortal/UserScreen/UserScreen.tsx index a1605fa59d..8543803933 100644 --- a/src/screens/UserPortal/UserScreen/UserScreen.tsx +++ b/src/screens/UserPortal/UserScreen/UserScreen.tsx @@ -1,41 +1,84 @@ import React, { useEffect, useState } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; +import { useSelector } from 'react-redux'; import { Navigate, Outlet, useLocation, useParams } from 'react-router-dom'; import { updateTargets } from 'state/action-creators'; +import { useAppDispatch } from 'state/hooks'; import type { RootState } from 'state/reducers'; import type { TargetsType } from 'state/reducers/routesReducer'; import styles from './UserScreen.module.css'; import { Button } from 'react-bootstrap'; import UserSidebarOrg from 'components/UserPortal/UserSidebarOrg/UserSidebarOrg'; import ProfileDropdown from 'components/ProfileDropdown/ProfileDropdown'; +import type { InterfaceMapType } from 'utils/interfaces'; +import { useTranslation } from 'react-i18next'; +const map: InterfaceMapType = { + organization: 'home', + people: 'people', + events: 'userEvents', + donate: 'donate', + campaigns: 'userCampaigns', + pledges: 'userPledges', +}; + +/** + * The UserScreen component serves as a container for user-specific pages + * within an organization context. It provides layout and sidebar navigation + * functionality based on the current organization ID and user roles. + * + * @returns The UserScreen component. + */ const UserScreen = (): JSX.Element => { + // Get the current location path for debugging or conditional rendering const location = useLocation(); - const [hideDrawer, setHideDrawer] = useState(null); + + /** + * State to manage the visibility of the sidebar (drawer). + */ + const { orgId } = useParams(); + // Redirect to home if orgId is not present if (!orgId) { return ; } - const appRoutes: { + const titleKey: string | undefined = map[location.pathname.split('/')[2]]; + const { t } = useTranslation('translation', { keyPrefix: titleKey }); + + const userRoutes: { targets: TargetsType[]; } = useSelector((state: RootState) => state.userRoutes); - const { targets } = appRoutes; - console.log(location.pathname.split('/')); + const { targets } = userRoutes; + const [hideDrawer, setHideDrawer] = useState(null); + + /** + * Retrieves the organization ID from the URL parameters. + */ + + // Initialize Redux dispatch + const dispatch = useAppDispatch(); - const dispatch = useDispatch(); + /** + * Effect hook to update targets based on the organization ID. + * This hook is triggered when the orgId changes. + */ useEffect(() => { dispatch(updateTargets(orgId)); - }, [orgId]); // Added orgId to the dependency array + }, [orgId]); + /** + * Handles window resize events to toggle the sidebar visibility + * based on the screen width. + */ const handleResize = (): void => { if (window.innerWidth <= 820) { setHideDrawer(!hideDrawer); } }; + // Set up event listener for window resize and clean up on unmount useEffect(() => { handleResize(); window.addEventListener('resize', handleResize); @@ -85,7 +128,10 @@ const UserScreen = (): JSX.Element => { } `} data-testid="mainpageright" > -
    +
    +
    +

    {titleKey !== 'home' ? t('title') : ''}

    +
    diff --git a/src/screens/Users/Users.test.tsx b/src/screens/Users/Users.test.tsx index f130ed1df9..65558e6ea7 100644 --- a/src/screens/Users/Users.test.tsx +++ b/src/screens/Users/Users.test.tsx @@ -428,22 +428,21 @@ describe('Testing Users screen', () => { , ); + }); + await wait(); - await wait(); - - const searchBtn = screen.getByTestId('searchButton'); - - const searchInput = screen.getByTestId(/searchByName/i); + const searchBtn = screen.getByTestId('searchButton'); + const searchInput = screen.getByTestId(/searchByName/i); + await act(async () => { // Clear the search input userEvent.clear(searchInput); - // Search for a name that doesn't exist userEvent.type(screen.getByTestId(/searchByName/i), 'NonexistentName'); userEvent.click(searchBtn); - - expect(screen.queryByText(/No User Found/i)).toBeInTheDocument(); }); + + expect(screen.queryByText(/No User Found/i)).toBeInTheDocument(); }); test('Testing User data is not present', async () => { @@ -518,40 +517,63 @@ describe('Testing Users screen', () => { , ); + }); + await wait(); - await wait(); - - const searchInput = screen.getByTestId('filter'); - expect(searchInput).toBeInTheDocument(); + const searchInput = screen.getByTestId('filter'); + expect(searchInput).toBeInTheDocument(); - const inputText = screen.getByTestId('filterUsers'); + const inputText = screen.getByTestId('filterUsers'); + await act(async () => { fireEvent.click(inputText); - const toggleText = screen.getByTestId('admin'); + }); + + const toggleText = screen.getByTestId('admin'); + + await act(async () => { fireEvent.click(toggleText); + }); - expect(searchInput).toBeInTheDocument(); + expect(searchInput).toBeInTheDocument(); + await act(async () => { fireEvent.click(inputText); - let toggleTite = screen.getByTestId('superAdmin'); + }); + + let toggleTite = screen.getByTestId('superAdmin'); + + await act(async () => { fireEvent.click(toggleTite); + }); - expect(searchInput).toBeInTheDocument(); + expect(searchInput).toBeInTheDocument(); + await act(async () => { fireEvent.click(inputText); - toggleTite = screen.getByTestId('user'); + }); + + toggleTite = screen.getByTestId('user'); + + await act(async () => { fireEvent.click(toggleTite); + }); - expect(searchInput).toBeInTheDocument(); + expect(searchInput).toBeInTheDocument(); + await act(async () => { fireEvent.click(inputText); - toggleTite = screen.getByTestId('cancel'); - fireEvent.click(toggleTite); + }); - await wait(); + toggleTite = screen.getByTestId('cancel'); - expect(searchInput).toBeInTheDocument(); + await act(async () => { + fireEvent.click(toggleTite); }); + + await wait(); + + expect(searchInput).toBeInTheDocument(); }); test('check for rerendering', async () => { @@ -620,37 +642,63 @@ describe('Testing Users screen', () => { , ); + }); + await wait(); - await wait(); + const filterButton = screen.getByTestId('filterUsers'); - const filterButton = screen.getByTestId('filterUsers'); + await act(async () => { fireEvent.click(filterButton); + }); - const filterAdmin = screen.getByTestId('admin'); + const filterAdmin = screen.getByTestId('admin'); + + await act(async () => { fireEvent.click(filterAdmin); - await wait(); - expect(screen.getByText('Jane Doe')).toBeInTheDocument(); + }); + await wait(); + expect(screen.getByText('Jane Doe')).toBeInTheDocument(); + + await act(async () => { fireEvent.click(filterButton); - const filterSuperAdmin = screen.getByTestId('superAdmin'); + }); + + const filterSuperAdmin = screen.getByTestId('superAdmin'); + + await act(async () => { fireEvent.click(filterSuperAdmin); - await wait(); - expect(screen.getByText('John Doe')).toBeInTheDocument(); + }); + + await wait(); + expect(screen.getByText('John Doe')).toBeInTheDocument(); + await act(async () => { fireEvent.click(filterButton); - const filterUser = screen.getByTestId('user'); + }); + + const filterUser = screen.getByTestId('user'); + await act(async () => { fireEvent.click(filterUser); - await wait(); - expect(screen.getByText('Jack Smith')).toBeInTheDocument(); + }); + await wait(); + expect(screen.getByText('Jack Smith')).toBeInTheDocument(); + + await act(async () => { fireEvent.click(filterButton); - const filterCancel = screen.getByTestId('cancel'); + }); + + const filterCancel = screen.getByTestId('cancel'); + + await act(async () => { fireEvent.click(filterCancel); - await wait(); - expect(screen.getByText('John Doe')).toBeInTheDocument(); - expect(screen.getByText('Jane Doe')).toBeInTheDocument(); - expect(screen.getByText('Jack Smith')).toBeInTheDocument(); }); + + await wait(); + expect(screen.getByText('John Doe')).toBeInTheDocument(); + expect(screen.getByText('Jane Doe')).toBeInTheDocument(); + expect(screen.getByText('Jack Smith')).toBeInTheDocument(); }); test('Users should be sorted and filtered correctly', async () => { @@ -667,47 +715,63 @@ describe('Testing Users screen', () => { , ); + }); + await wait(); - await wait(); - - // Check if the sorting and filtering logic was applied correctly - const rows = screen.getAllByRole('row'); + // Check if the sorting and filtering logic was applied correctly + const rows = screen.getAllByRole('row'); - const firstRow = rows[1]; - const secondRow = rows[2]; + const firstRow = rows[1]; + const secondRow = rows[2]; - expect(firstRow).toHaveTextContent('John Doe'); - expect(secondRow).toHaveTextContent('Jane Doe'); + expect(firstRow).toHaveTextContent('John Doe'); + expect(secondRow).toHaveTextContent('Jane Doe'); - await wait(); + await wait(); - const inputText = screen.getByTestId('sortUsers'); + const inputText = screen.getByTestId('sortUsers'); + await act(async () => { fireEvent.click(inputText); - const toggleText = screen.getByTestId('oldest'); - fireEvent.click(toggleText); + }); + + const toggleText = screen.getByTestId('oldest'); + await act(async () => { + fireEvent.click(toggleText); fireEvent.click(inputText); - const toggleTite = screen.getByTestId('newest'); + }); + + const toggleTite = screen.getByTestId('newest'); + + await act(async () => { fireEvent.click(toggleTite); + }); - // Verify the users are sorted by oldest - await wait(); + // Verify the users are sorted by oldest + await wait(); - const displayedUsers = screen.getAllByRole('row'); - expect(displayedUsers[1]).toHaveTextContent('John Doe'); // assuming User1 is the oldest - expect(displayedUsers[displayedUsers.length - 1]).toHaveTextContent( - 'Jack Smith', - ); // assuming UserN is the newest + const displayedUsers = screen.getAllByRole('row'); + expect(displayedUsers[1]).toHaveTextContent('John Doe'); // assuming User1 is the oldest + expect(displayedUsers[displayedUsers.length - 1]).toHaveTextContent( + 'Jack Smith', + ); // assuming UserN is the newest - await wait(); + await wait(); + await act(async () => { fireEvent.click(inputText); - const toggleOld = screen.getByTestId('oldest'); - fireEvent.click(toggleOld); + }); + + const toggleOld = screen.getByTestId('oldest'); + await act(async () => { + fireEvent.click(toggleOld); fireEvent.click(inputText); - const toggleNewest = screen.getByTestId('newest'); + }); + + const toggleNewest = screen.getByTestId('newest'); + await act(async () => { fireEvent.click(toggleNewest); }); }); diff --git a/src/screens/Users/Users.tsx b/src/screens/Users/Users.tsx index 3dae6ec17e..72acba5b5c 100644 --- a/src/screens/Users/Users.tsx +++ b/src/screens/Users/Users.tsx @@ -19,7 +19,48 @@ import type { InterfaceQueryUserListItem } from 'utils/interfaces'; import styles from './Users.module.css'; import useLocalStorage from 'utils/useLocalstorage'; import type { ApolloError } from '@apollo/client'; - +/** + * The `Users` component is responsible for displaying a list of users in a paginated and sortable format. + * It supports search functionality, filtering, and sorting of users. The component integrates with GraphQL + * for fetching and managing user data and displays results with infinite scrolling. + * + * ## Features: + * - **Search:** Allows users to search for users by their first name. + * - **Sorting:** Provides options to sort users by creation date (newest or oldest). + * - **Filtering:** Enables filtering users based on their roles (admin, superadmin, user, etc.). + * - **Pagination:** Utilizes infinite scrolling to load more users as the user scrolls down. + * + * ## GraphQL Queries: + * - `USER_LIST`: Fetches a list of users with specified search, sorting, and pagination parameters. + * - `ORGANIZATION_CONNECTION_LIST`: Fetches a list of organizations to verify organization existence. + * + * + * ## Component State: + * - `isLoading`: Indicates whether the component is currently loading data. + * - `hasMore`: Indicates if there are more users to load. + * - `isLoadingMore`: Indicates if more users are currently being loaded. + * - `searchByName`: The current search query for user names. + * - `sortingOption`: The current sorting option (newest or oldest). + * - `filteringOption`: The current filtering option (admin, superadmin, user, cancel). + * - `displayedUsers`: The list of users currently displayed, filtered and sorted. + * + * ## Event Handlers: + * - `handleSearch`: Handles searching users by name and refetches the user list. + * - `handleSearchByEnter`: Handles search input when the Enter key is pressed. + * - `handleSearchByBtnClick`: Handles search input when the search button is clicked. + * - `resetAndRefetch`: Resets search and refetches the user list with default parameters. + * - `loadMoreUsers`: Loads more users when scrolling reaches the end of the list. + * - `handleSorting`: Updates sorting option and refetches the user list. + * - `handleFiltering`: Updates filtering option and refetches the user list. + * + * ## Rendering: + * - Displays a search input and button for searching users. + * - Provides dropdowns for sorting and filtering users. + * - Renders a table of users with infinite scrolling support. + * - Shows appropriate messages when no users are found or when search yields no results. + * + * @returns The rendered `Users` component. + */ const Users = (): JSX.Element => { const { t } = useTranslation('translation', { keyPrefix: 'users' }); const { t: tCommon } = useTranslation('common'); @@ -96,7 +137,7 @@ const Users = (): JSX.Element => { } if (dataOrgs.organizationsConnection.length === 0) { - toast.warning(t('noOrgError')); + toast.warning(t('noOrgError') as string); } }, [dataOrgs]); diff --git a/src/state/hooks.ts b/src/state/hooks.ts new file mode 100644 index 0000000000..161703cc49 --- /dev/null +++ b/src/state/hooks.ts @@ -0,0 +1,5 @@ +import { useDispatch } from 'react-redux'; +import type { AppDispatch } from './store'; + +// Use throughout your app instead of plain `useDispatch` +export const useAppDispatch = useDispatch.withTypes(); diff --git a/src/state/reducers/routesReducer.test.ts b/src/state/reducers/routesReducer.test.ts index 84427ee4d0..8bdc1c069b 100644 --- a/src/state/reducers/routesReducer.test.ts +++ b/src/state/reducers/routesReducer.test.ts @@ -13,10 +13,10 @@ describe('Testing Routes reducer', () => { { name: 'My Organizations', url: '/orglist' }, { name: 'Dashboard', url: '/orgdash/undefined' }, { name: 'People', url: '/orgpeople/undefined' }, + { name: 'Tags', url: '/orgtags/undefined' }, { name: 'Events', url: '/orgevents/undefined' }, { name: 'Venues', url: '/orgvenues/undefined' }, { name: 'Action Items', url: '/orgactionitems/undefined' }, - { name: 'Agenda Items Category', url: '/orgagendacategory/undefined' }, { name: 'Posts', url: '/orgpost/undefined' }, { name: 'Block/Unblock', @@ -49,6 +49,11 @@ describe('Testing Routes reducer', () => { comp_id: 'orgpeople', component: 'OrganizationPeople', }, + { + name: 'Tags', + comp_id: 'orgtags', + component: 'OrganizationTags', + }, { name: 'Events', comp_id: 'orgevents', @@ -64,11 +69,6 @@ describe('Testing Routes reducer', () => { comp_id: 'orgactionitems', component: 'OrganizationActionItems', }, - { - name: 'Agenda Items Category', - comp_id: 'orgagendacategory', - component: 'OrganizationAgendaCategory', - }, { name: 'Posts', comp_id: 'orgpost', component: 'OrgPost' }, { name: 'Block/Unblock', comp_id: 'blockuser', component: 'BlockUser' }, { @@ -116,10 +116,10 @@ describe('Testing Routes reducer', () => { { name: 'My Organizations', url: '/orglist' }, { name: 'Dashboard', url: '/orgdash/orgId' }, { name: 'People', url: '/orgpeople/orgId' }, + { name: 'Tags', url: '/orgtags/orgId' }, { name: 'Events', url: '/orgevents/orgId' }, { name: 'Venues', url: '/orgvenues/orgId' }, { name: 'Action Items', url: '/orgactionitems/orgId' }, - { name: 'Agenda Items Category', url: '/orgagendacategory/orgId' }, { name: 'Posts', url: '/orgpost/orgId' }, { name: 'Block/Unblock', url: '/blockuser/orgId' }, { name: 'Advertisement', url: '/orgads/orgId' }, @@ -149,6 +149,11 @@ describe('Testing Routes reducer', () => { comp_id: 'orgpeople', component: 'OrganizationPeople', }, + { + name: 'Tags', + comp_id: 'orgtags', + component: 'OrganizationTags', + }, { name: 'Events', comp_id: 'orgevents', @@ -164,11 +169,6 @@ describe('Testing Routes reducer', () => { comp_id: 'orgactionitems', component: 'OrganizationActionItems', }, - { - name: 'Agenda Items Category', - comp_id: 'orgagendacategory', - component: 'OrganizationAgendaCategory', - }, { name: 'Posts', comp_id: 'orgpost', component: 'OrgPost' }, { name: 'Block/Unblock', comp_id: 'blockuser', component: 'BlockUser' }, { @@ -212,10 +212,10 @@ describe('Testing Routes reducer', () => { { name: 'My Organizations', url: '/orglist' }, { name: 'Dashboard', url: '/orgdash/undefined' }, { name: 'People', url: '/orgpeople/undefined' }, + { name: 'Tags', url: '/orgtags/undefined' }, { name: 'Events', url: '/orgevents/undefined' }, { name: 'Venues', url: '/orgvenues/undefined' }, { name: 'Action Items', url: '/orgactionitems/undefined' }, - { name: 'Agenda Items Category', url: '/orgagendacategory/undefined' }, { name: 'Posts', url: '/orgpost/undefined' }, { name: 'Block/Unblock', @@ -251,6 +251,11 @@ describe('Testing Routes reducer', () => { comp_id: 'orgpeople', component: 'OrganizationPeople', }, + { + name: 'Tags', + comp_id: 'orgtags', + component: 'OrganizationTags', + }, { name: 'Events', comp_id: 'orgevents', @@ -266,11 +271,6 @@ describe('Testing Routes reducer', () => { comp_id: 'orgactionitems', component: 'OrganizationActionItems', }, - { - name: 'Agenda Items Category', - comp_id: 'orgagendacategory', - component: 'OrganizationAgendaCategory', - }, { name: 'Posts', comp_id: 'orgpost', component: 'OrgPost' }, { name: 'Block/Unblock', comp_id: 'blockuser', component: 'BlockUser' }, { diff --git a/src/state/reducers/routesReducer.ts b/src/state/reducers/routesReducer.ts index bcda9f02d8..5d50f5402d 100644 --- a/src/state/reducers/routesReducer.ts +++ b/src/state/reducers/routesReducer.ts @@ -69,6 +69,7 @@ const components: ComponentType[] = [ { name: 'My Organizations', comp_id: 'orglist', component: 'OrgList' }, { name: 'Dashboard', comp_id: 'orgdash', component: 'OrganizationDashboard' }, { name: 'People', comp_id: 'orgpeople', component: 'OrganizationPeople' }, + { name: 'Tags', comp_id: 'orgtags', component: 'OrganizationTags' }, { name: 'Events', comp_id: 'orgevents', component: 'OrganizationEvents' }, { name: 'Venues', comp_id: 'orgvenues', component: 'OrganizationVenues' }, { @@ -76,11 +77,6 @@ const components: ComponentType[] = [ comp_id: 'orgactionitems', component: 'OrganizationActionItems', }, - { - name: 'Agenda Items Category', - comp_id: 'orgagendacategory', - component: 'OrganizationAgendaCategory', - }, { name: 'Posts', comp_id: 'orgpost', component: 'OrgPost' }, { name: 'Block/Unblock', comp_id: 'blockuser', component: 'BlockUser' }, { name: 'Advertisement', comp_id: 'orgads', component: 'Advertisements' }, diff --git a/src/state/reducers/userRoutersReducer.test.ts b/src/state/reducers/userRoutersReducer.test.ts index f819af8564..98c4a78464 100644 --- a/src/state/reducers/userRoutersReducer.test.ts +++ b/src/state/reducers/userRoutersReducer.test.ts @@ -15,6 +15,8 @@ describe('Testing Routes reducer', () => { { name: 'People', url: 'user/people/undefined' }, { name: 'Events', url: 'user/events/undefined' }, { name: 'Donate', url: 'user/donate/undefined' }, + { name: 'Campaigns', url: 'user/campaigns/undefined' }, + { name: 'My Pledges', url: 'user/pledges/undefined' }, ], components: [ { @@ -30,6 +32,12 @@ describe('Testing Routes reducer', () => { { name: 'People', comp_id: 'people', component: 'People' }, { name: 'Events', comp_id: 'events', component: 'Events' }, { name: 'Donate', comp_id: 'donate', component: 'Donate' }, + { + name: 'Campaigns', + comp_id: 'campaigns', + component: 'Campaigns', + }, + { name: 'My Pledges', comp_id: 'pledges', component: 'Pledges' }, ], }); }); @@ -47,6 +55,8 @@ describe('Testing Routes reducer', () => { { name: 'People', url: 'user/people/orgId' }, { name: 'Events', url: 'user/events/orgId' }, { name: 'Donate', url: 'user/donate/orgId' }, + { name: 'Campaigns', url: 'user/campaigns/orgId' }, + { name: 'My Pledges', url: 'user/pledges/orgId' }, ], components: [ { @@ -62,6 +72,12 @@ describe('Testing Routes reducer', () => { { name: 'People', comp_id: 'people', component: 'People' }, { name: 'Events', comp_id: 'events', component: 'Events' }, { name: 'Donate', comp_id: 'donate', component: 'Donate' }, + { + name: 'Campaigns', + comp_id: 'campaigns', + component: 'Campaigns', + }, + { name: 'My Pledges', comp_id: 'pledges', component: 'Pledges' }, ], }); }); diff --git a/src/state/reducers/userRoutesReducer.ts b/src/state/reducers/userRoutesReducer.ts index e85d4c25d9..44bc91fabb 100644 --- a/src/state/reducers/userRoutesReducer.ts +++ b/src/state/reducers/userRoutesReducer.ts @@ -56,6 +56,12 @@ const components: ComponentType[] = [ { name: 'People', comp_id: 'people', component: 'People' }, { name: 'Events', comp_id: 'events', component: 'Events' }, { name: 'Donate', comp_id: 'donate', component: 'Donate' }, + { + name: 'Campaigns', + comp_id: 'campaigns', + component: 'Campaigns', + }, + { name: 'My Pledges', comp_id: 'pledges', component: 'Pledges' }, ]; const generateRoutes = ( diff --git a/src/state/store.ts b/src/state/store.ts index 4ec777453a..fa4329c693 100644 --- a/src/state/store.ts +++ b/src/state/store.ts @@ -1,5 +1,8 @@ -import { applyMiddleware, createStore } from 'redux'; -import thunk from 'redux-thunk'; +import { configureStore } from '@reduxjs/toolkit'; import { reducers } from './reducers/index'; -export const store = createStore(reducers, {}, applyMiddleware(thunk)); +export const store = configureStore({ + reducer: reducers, +}); + +export type AppDispatch = typeof store.dispatch; diff --git a/src/utils/StaticMockLink.ts b/src/utils/StaticMockLink.ts index 31773d3978..457da3dfd4 100644 --- a/src/utils/StaticMockLink.ts +++ b/src/utils/StaticMockLink.ts @@ -84,7 +84,7 @@ export class StaticMockLink extends ApolloLink { } else { const { newData } = response; if (newData) { - response.result = newData(); + response.result = newData(operation.variables); this._mockedResponsesByKey[key].push(response); } @@ -118,7 +118,9 @@ export class StaticMockLink extends ApolloLink { if (response.result) { observer.next( typeof response.result === 'function' - ? (response.result as ResultFunction)() + ? (response.result as ResultFunction)( + operation.variables, + ) : response.result, ); } diff --git a/src/utils/errorHandler.test.tsx b/src/utils/errorHandler.test.tsx index 1ca42441ab..45f46e6389 100644 --- a/src/utils/errorHandler.test.tsx +++ b/src/utils/errorHandler.test.tsx @@ -1,4 +1,5 @@ -import type { TFunction } from 'react-i18next'; +type TFunction = (key: string, options?: Record) => string; + import { errorHandler } from './errorHandler'; import { toast } from 'react-toastify'; @@ -9,8 +10,9 @@ jest.mock('react-toastify', () => ({ })); describe('Test if errorHandler is working properly', () => { - const t: TFunction<'translation', string> = (key: string) => key; - const tErrors: TFunction<'errors', string> = (key: string) => key; + const t: TFunction = (key: string) => key; + const tErrors: TFunction = (key: string, options?: Record) => + key; it('should call toast.error with the correct message if error message is "Failed to fetch"', () => { const error = new Error('Failed to fetch'); diff --git a/src/utils/errorHandler.tsx b/src/utils/errorHandler.tsx index aa7c6dc9dc..b7a22210a8 100644 --- a/src/utils/errorHandler.tsx +++ b/src/utils/errorHandler.tsx @@ -1,23 +1,24 @@ -import type { TFunction } from 'react-i18next'; +type TFunction = (key: string, options?: Record) => string; + import { toast } from 'react-toastify'; import i18n from './i18n'; -/* +/** This function is used to handle api errors in the application. It takes in the error object and displays the error message to the user. If the error is due to the Talawa API being unavailable, it displays a custom message. */ export const errorHandler = (a: unknown, error: unknown): void => { - const tErrors: TFunction = i18n.getFixedT(null, 'errors'); + const tErrors: TFunction = i18n.getFixedT(null, 'errors'); if (error instanceof Error) { switch (error.message) { case 'Failed to fetch': - toast.error(tErrors('talawaApiUnavailable')); + toast.error(tErrors('talawaApiUnavailable') as string); break; // Add more cases as needed default: toast.error(error.message); } } else { - toast.error(tErrors('unknownError', { msg: error })); + toast.error(tErrors('unknownError', { msg: error }) as string); } }; diff --git a/src/utils/interfaces.ts b/src/utils/interfaces.ts index 82cfd555da..ad876ee2f2 100644 --- a/src/utils/interfaces.ts +++ b/src/utils/interfaces.ts @@ -11,6 +11,8 @@ export interface InterfaceActionItemCategoryInfo { _id: string; name: string; isDisabled: boolean; + createdAt: string; + creator: { _id: string; firstName: string; lastName: string }; } export interface InterfaceActionItemCategoryList { @@ -23,18 +25,20 @@ export interface InterfaceActionItemInfo { _id: string; firstName: string; lastName: string; + image: string | null; }; assigner: { _id: string; firstName: string; lastName: string; + image: string | null; }; actionItemCategory: { _id: string; name: string; }; preCompletionNotes: string; - postCompletionNotes: string; + postCompletionNotes: string | null; assignmentDate: Date; dueDate: Date; completionDate: Date; @@ -42,12 +46,13 @@ export interface InterfaceActionItemInfo { event: { _id: string; title: string; - }; + } | null; creator: { _id: string; firstName: string; lastName: string; }; + allotedHours: number | null; } export interface InterfaceActionItemList { @@ -204,6 +209,72 @@ export interface InterfaceQueryOrganizationPostListItem { }; } +export interface InterfaceTagData { + _id: string; + name: string; + usersAssignedTo: { + totalCount: number; + }; + childTags: { + totalCount: number; + }; +} + +interface InterfaceTagNodeData { + edges: { + node: InterfaceTagData; + cursor: string; + }[]; + pageInfo: { + startCursor: string; + endCursor: string; + hasNextPage: boolean; + hasPreviousPage: boolean; + }; + totalCount: number; +} + +interface InterfaceTagMembersData { + edges: { + node: { + _id: string; + firstName: string; + lastName: string; + }; + }[]; + pageInfo: { + startCursor: string; + endCursor: string; + hasNextPage: boolean; + hasPreviousPage: boolean; + }; + totalCount: number; +} + +export interface InterfaceQueryOrganizationUserTags { + userTags: InterfaceTagNodeData; +} + +export interface InterfaceQueryUserTagChildTags { + name: string; + childTags: InterfaceTagNodeData; +} + +export interface InterfaceQueryUserTagsAssignedMembers { + name: string; + usersAssignedTo: InterfaceTagMembersData; +} + +export interface InterfaceQueryUserTagsMembersToAssignTo { + name: string; + usersToAssignTo: InterfaceTagMembersData; +} + +export interface InterfaceQueryUserTagsMembersToAssignTo { + name: string; + usersToAssignTo: InterfaceTagMembersData; +} + export interface InterfaceQueryOrganizationAdvertisementListItem { advertisements: { edges: { @@ -226,20 +297,10 @@ export interface InterfaceQueryOrganizationAdvertisementListItem { totalCount: number; }; } -export interface InterfaceQueryOrganizationFunds { - fundsByOrganization: { - _id: string; - name: string; - refrenceNumber: string; - taxDeductible: boolean; - isArchived: boolean; - isDefault: boolean; - createdAt: string; - organizationId: string; - creator: { _id: string; firstName: string; lastName: string }; - }[]; -} + export interface InterfaceQueryOrganizationFundCampaigns { + name: string; + isArchived: boolean; campaigns: { _id: string; name: string; @@ -250,17 +311,24 @@ export interface InterfaceQueryOrganizationFundCampaigns { currency: string; }[]; } +export interface InterfaceUserCampaign { + _id: string; + name: string; + fundingGoal: number; + startDate: Date; + endDate: Date; + currency: string; +} export interface InterfaceQueryFundCampaignsPledges { + fundId: { + name: string; + }; + name: string; + fundingGoal: number; + currency: string; startDate: Date; endDate: Date; - pledges: { - _id: string; - amount: number; - currency: string; - endDate: string; - startDate: string; - users: InterfacePledgeVolunteer[]; - }[]; + pledges: InterfacePledgeInfo[]; } export interface InterfaceFundInfo { _id: string; @@ -270,6 +338,8 @@ export interface InterfaceFundInfo { isArchived: boolean; isDefault: boolean; createdAt: string; + organizationId: string; + creator: { _id: string; firstName: string; lastName: string }; } export interface InterfaceCampaignInfo { _id: string; @@ -282,11 +352,12 @@ export interface InterfaceCampaignInfo { } export interface InterfacePledgeInfo { _id: string; + campaign?: { _id: string; name: string; endDate: Date }; amount: number; currency: string; endDate: string; startDate: string; - users: InterfacePledgeVolunteer[]; + users: InterfacePledger[]; } export interface InterfaceQueryOrganizationEventListItem { _id: string; @@ -383,6 +454,9 @@ export interface InterfaceAddress { export interface InterfaceCreateFund { fundName: string; fundRef: string; + isDefault: boolean; + isArchived: boolean; + taxDeductible: boolean; } export interface InterfacePostCard { @@ -403,7 +477,7 @@ export interface InterfacePostCard { comments: { id: string; creator: { - _id: string; + id: string; firstName: string; lastName: string; email: string; @@ -421,16 +495,9 @@ export interface InterfacePostCard { }[]; fetchPosts: () => void; } -export interface InterfaceCreateCampaign { - campaignName: string; - campaignCurrency: string; - campaignGoal: number; - campaignStartDate: Date; - campaignEndDate: Date; -} export interface InterfaceCreatePledge { - pledgeUsers: InterfacePledgeVolunteer[]; + pledgeUsers: InterfacePledger[]; pledgeAmount: number; pledgeCurrency: string; pledgeStartDate: Date; @@ -452,12 +519,13 @@ export interface InterfaceQueryMembershipRequestsListItem { }[]; } -export interface InterfacePledgeVolunteer { +export interface InterfacePledger { _id: string; firstName: string; lastName: string; image: string | null; } + export interface InterfaceAgendaItemCategoryInfo { _id: string; name: string; @@ -485,4 +553,48 @@ export interface InterfaceFormData { email: string; phoneNo: string; gender: string; + +export interface InterfaceAgendaItemInfo { + _id: string; + title: string; + description: string; + duration: string; + attachments: string[]; + createdBy: { + _id: string; + firstName: string; + lastName: string; + }; + urls: string[]; + users: { + _id: string; + firstName: string; + lastName: string; + }[]; + sequence: number; + categories: { + _id: string; + name: string; + }[]; + organization: { + _id: string; + name: string; + }; + relatedEvent: { + _id: string; + title: string; + }; +} + +export interface InterfaceAgendaItemList { + agendaItemByEvent: InterfaceAgendaItemInfo[]; +} + +export interface InterfaceMapType { + [key: string]: string; +} + +export interface InterfaceCustomFieldData { + type: string; + name: string; } diff --git a/src/utils/organizationTagsUtils.ts b/src/utils/organizationTagsUtils.ts new file mode 100644 index 0000000000..fc987f37b5 --- /dev/null +++ b/src/utils/organizationTagsUtils.ts @@ -0,0 +1,28 @@ +// This file will contain the utililities for organization tags + +// This is the style object for mui's data grid used to list the data (tags and member data) +export const dataGridStyle = { + '&.MuiDataGrid-root .MuiDataGrid-cell:focus-within': { + outline: 'none !important', + }, + '&.MuiDataGrid-root .MuiDataGrid-columnHeader:focus-within': { + outline: 'none', + }, + '& .MuiDataGrid-row:hover': { + backgroundColor: 'transparent', + }, + '& .MuiDataGrid-row.Mui-hovered': { + backgroundColor: 'transparent', + }, + '& .MuiDataGrid-root': { + borderRadius: '0.1rem', + }, + '& .MuiDataGrid-main': { + borderRadius: '0.1rem', + }, +}; + +export const ADD_PEOPLE_TO_TAGS_QUERY_LIMIT = 7; +export const TAGS_QUERY_LIMIT = 10; + +export type TagActionType = 'assignToTags' | 'removeFromTags'; diff --git a/src/utils/timezoneUtils/dateTimeConfig.ts b/src/utils/timezoneUtils/dateTimeConfig.ts new file mode 100644 index 0000000000..8d352bcde6 --- /dev/null +++ b/src/utils/timezoneUtils/dateTimeConfig.ts @@ -0,0 +1,28 @@ +// dateTimeConfig.ts + +export const dateTimeFields = { + directFields: [ + 'createdAt', + 'birthDate', + 'updatedAt', + 'recurrenceStartDate', + 'recurrenceEndDate', + 'pluginCreatedBy', + 'dueDate', + 'completionDate', + 'startCursor', + 'endCursor', + ], + pairedFields: [ + { + dateField: 'startDate', + timeField: 'startTime', + combinedField: 'startDateTime', + }, + { + dateField: 'endDate', + timeField: 'endTime', + combinedField: 'endDateTime', + }, + ], +}; diff --git a/src/utils/timezoneUtils/dateTimeMiddleware.test.ts b/src/utils/timezoneUtils/dateTimeMiddleware.test.ts new file mode 100644 index 0000000000..b14702b546 --- /dev/null +++ b/src/utils/timezoneUtils/dateTimeMiddleware.test.ts @@ -0,0 +1,226 @@ +import { requestMiddleware, responseMiddleware } from './dateTimeMiddleware'; +import type { Operation, FetchResult } from '@apollo/client/core'; +import { Observable } from '@apollo/client/core'; +import { gql } from '@apollo/client'; +import type { DocumentNode } from 'graphql'; + +const DUMMY_QUERY: DocumentNode = gql` + query GetDummyData { + dummyData { + id + } + } +`; + +describe('Date Time Middleware Tests', () => { + describe('Request Middleware', () => { + it('should convert local date and time to UTC format in request variables', () => { + const operation: Operation = { + query: DUMMY_QUERY, + operationName: 'GetDummyData', + variables: { startDate: '2023-09-01', startTime: '12:00:00' }, + getContext: jest.fn(() => ({})), + setContext: jest.fn(), + extensions: {}, + }; + + const forward = jest.fn( + (op) => + new Observable((observer) => { + expect(op.variables['startDate']).toBe('2023-09-01'); + expect(op.variables['startTime']).toMatch( + /\d{2}:\d{2}:\d{2}.\d{3}Z/, + ); + observer.complete(); + }), + ); + + const observable = requestMiddleware.request(operation, forward); + expect(observable).not.toBeNull(); + observable?.subscribe(() => { + expect(forward).toHaveBeenCalled(); + }); + }); + }); + + describe('Response Middleware', () => { + it('should convert UTC date and time to local format in response data', () => { + const testResponse: FetchResult = { + data: { createdAt: '2023-09-01T12:00:00.000Z' }, + extensions: {}, + context: {}, + }; + + const operation: Operation = { + query: DUMMY_QUERY, + operationName: 'GetDummyData', + variables: {}, + getContext: jest.fn(() => ({})), + setContext: jest.fn(), + extensions: {}, + }; + + const forward = jest.fn( + () => + new Observable((observer) => { + observer.next(testResponse); + observer.complete(); + }), + ); + + const observable = responseMiddleware.request(operation, forward); + expect(observable).not.toBeNull(); + return new Promise((resolve, reject) => { + observable?.subscribe({ + next: (response: FetchResult) => { + if (!response.data) { + reject(new Error('Expected response.data to be defined')); + return; + } + + // Now it's safe to assume response.data exists for the following expectations + expect(response.data['createdAt']).not.toBe( + '2023-09-01T12:00:00.000Z', + ); + resolve(); + }, + error: reject, + }); + }).then(() => { + expect(forward).toHaveBeenCalled(); + }); + }); + }); + + describe('Date Time Middleware Edge Cases', () => { + it('should handle invalid date formats gracefully in request middleware', () => { + const operation: Operation = { + query: DUMMY_QUERY, + operationName: 'GetDummyData', + variables: { startDate: 'not-a-date', startTime: '25:99:99' }, + getContext: jest.fn(() => ({})), + setContext: jest.fn(), + extensions: {}, + }; + + const forward = jest.fn( + (op) => + new Observable((observer) => { + expect(op.variables['startDate']).toBe('not-a-date'); + expect(op.variables['startTime']).toBe('25:99:99'); + observer.complete(); + }), + ); + + const observable = requestMiddleware.request(operation, forward); + expect(observable).not.toBeNull(); + observable?.subscribe(() => { + expect(forward).toHaveBeenCalled(); + }); + }); + + it('should not break when encountering invalid dates in response middleware', () => { + const testResponse: FetchResult = { + data: { createdAt: 'invalid-date-time' }, + extensions: {}, + context: {}, + }; + + const operation: Operation = { + query: DUMMY_QUERY, + operationName: 'GetDummyData', + variables: {}, + getContext: jest.fn(() => ({})), + setContext: jest.fn(), + extensions: {}, + }; + + const forward = jest.fn( + () => + new Observable((observer) => { + observer.next(testResponse); + observer.complete(); + }), + ); + + const observable = responseMiddleware.request(operation, forward); + + expect(observable).not.toBeNull(); + return new Promise((resolve, reject) => { + observable?.subscribe({ + next: (response: FetchResult) => { + // Ensure there's always an assertion + expect(response.data).toBeTruthy(); // This ensures `response.data` is defined and truthy + + if (!response.data) { + // Explicitly throw an error if response.data is null or undefined + reject(new Error('Expected response.data to be defined')); + return; + } + + // Now it's safe to assume response.data exists for the following expectations + expect(response.data['createdAt']).toBe('invalid-date-time'); + resolve(); + }, + error: reject, + }); + }).then(() => { + expect(forward).toHaveBeenCalled(); + }); + }); + }); + + describe('Recursive Date Conversion in Nested Objects', () => { + it('should recursively convert date and time in deeply nested objects in request middleware', () => { + const operation: Operation = { + query: DUMMY_QUERY, + operationName: 'GetDummyData', + variables: { + event: { + startDate: '2023-10-01', + startTime: '08:00:00', + details: { + endDate: '2023-10-01', + endTime: '18:00:00', + additionalInfo: { + createdAt: '2023-10-01T08:00:00.000Z', + }, + }, + }, + }, + getContext: jest.fn(() => ({})), + setContext: jest.fn(), + extensions: {}, + }; + + const forward = jest.fn( + (op) => + new Observable((observer) => { + expect(op.variables.event.startDate).toBe('2023-10-01'); + expect(op.variables.event.startTime).toMatch( + /\d{2}:\d{2}:\d{2}.\d{3}Z/, + ); + expect(op.variables.event.details.endDate).toBe('2023-10-01'); + expect(op.variables.event.details.endTime).toMatch( + /\d{2}:\d{2}:\d{2}.\d{3}Z/, + ); + expect(op.variables.event.details.additionalInfo.createdAt).toMatch( + /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/, + ); + observer.complete(); + }), + ); + + const observable = requestMiddleware.request(operation, forward); + expect(observable).not.toBeNull(); + return new Promise((resolve, reject) => { + observable?.subscribe({ + complete: resolve, + error: reject, + }); + }).then(() => { + expect(forward).toHaveBeenCalled(); + }); + }); + }); +}); diff --git a/src/utils/timezoneUtils/dateTimeMiddleware.ts b/src/utils/timezoneUtils/dateTimeMiddleware.ts new file mode 100644 index 0000000000..70fc20a026 --- /dev/null +++ b/src/utils/timezoneUtils/dateTimeMiddleware.ts @@ -0,0 +1,99 @@ +import { ApolloLink } from '@apollo/client/core'; +import dayjs from 'dayjs'; +import utc from 'dayjs/plugin/utc'; +import timezone from 'dayjs/plugin/timezone'; +import { dateTimeFields } from './dateTimeConfig'; + +// Extend dayjs with the necessary plugins +dayjs.extend(utc); +dayjs.extend(timezone); + +const combineDateTime = (date: string, time: string): string => { + return `${date}T${time}`; +}; + +const splitDateTime = (dateTimeStr: string): { date: string; time: string } => { + const dateTime = dayjs.utc(dateTimeStr); + return { + date: dateTime.format('YYYY-MM-DD'), + time: dateTime.format('HH:mm:ss.SSS[Z]'), + }; +}; + +const convertUTCToLocal = (dateStr: string): string => { + if (dayjs(dateStr).isValid()) { + return dayjs.utc(dateStr).local().format('YYYY-MM-DDTHH:mm:ss.SSS'); + } + return dateStr; +}; + +const convertLocalToUTC = (dateStr: string): string => { + if (dayjs(dateStr).isValid()) { + const result = dayjs(dateStr).utc().format('YYYY-MM-DDTHH:mm:ss.SSS[Z]'); + return result; + } + return dateStr; +}; + +const traverseAndConvertDates = ( + obj: Record, + convertFn: (dateStr: string) => string, + splitFn: (dateTimeStr: string) => { date: string; time: string }, +): void => { + if (typeof obj !== 'object' || obj === null) return; + + Object.keys(obj).forEach((key) => { + const value = obj[key]; + + // Handle paired date and time fields + dateTimeFields.pairedFields.forEach(({ dateField, timeField }) => { + if (key === dateField && obj[timeField]) { + const combinedDateTime = combineDateTime( + obj[dateField] as string, + obj[timeField] as string, + ); + const convertedDateTime = convertFn(combinedDateTime); + const { date, time } = splitFn(convertedDateTime); + obj[dateField] = date; // Restore the original date field + obj[timeField] = time; // Restore the original time field + } + }); + + // Convert simple date/time fields + if (dateTimeFields.directFields.includes(key)) { + obj[key] = convertFn(value as string); + } + + if (typeof value === 'object' && value !== null) { + traverseAndConvertDates( + value as Record, + convertFn, + splitFn, + ); // Recursive call for nested objects/arrays + } + }); +}; + +// Request middleware to convert local time to UTC time +export const requestMiddleware = new ApolloLink((operation, forward) => { + traverseAndConvertDates( + operation.variables, + convertLocalToUTC, + splitDateTime, + ); + return forward(operation); +}); + +// Response middleware to convert UTC time to local time +export const responseMiddleware = new ApolloLink((operation, forward) => { + return forward(operation).map((response) => { + if (response.data) { + traverseAndConvertDates( + response.data as Record, + convertUTCToLocal, + splitDateTime, + ); + } + return response; + }); +}); diff --git a/src/utils/timezoneUtils/index.ts b/src/utils/timezoneUtils/index.ts new file mode 100644 index 0000000000..887072b20c --- /dev/null +++ b/src/utils/timezoneUtils/index.ts @@ -0,0 +1,2 @@ +export * from './dateTimeConfig'; +export * from './dateTimeMiddleware'; diff --git a/src/utils/useSession.test.tsx b/src/utils/useSession.test.tsx new file mode 100644 index 0000000000..32287ccbb0 --- /dev/null +++ b/src/utils/useSession.test.tsx @@ -0,0 +1,544 @@ +import type { ReactNode } from 'react'; +import React from 'react'; +import { renderHook, act, waitFor } from '@testing-library/react'; +import { MockedProvider } from '@apollo/client/testing'; +import { toast } from 'react-toastify'; +import useSession from './useSession'; +import { GET_COMMUNITY_SESSION_TIMEOUT_DATA } from 'GraphQl/Queries/Queries'; +import { REVOKE_REFRESH_TOKEN } from 'GraphQl/Mutations/mutations'; +import { errorHandler } from 'utils/errorHandler'; +import { BrowserRouter } from 'react-router-dom'; + +jest.mock('react-toastify', () => ({ + toast: { + info: jest.fn(), + warning: jest.fn(), + error: jest.fn(), + }, +})); + +jest.mock('utils/errorHandler', () => ({ + errorHandler: jest.fn(), +})); + +jest.mock('react-i18next', () => ({ + useTranslation: () => ({ + t: (key: string) => key, + }), +})); + +const MOCKS = [ + { + request: { + query: GET_COMMUNITY_SESSION_TIMEOUT_DATA, + }, + result: { + data: { + getCommunityData: { + timeout: 30, + }, + }, + }, + delay: 100, + }, + { + request: { + query: REVOKE_REFRESH_TOKEN, + }, + result: { + data: { + revokeRefreshTokenForUser: true, + }, + }, + }, +]; + +const wait = (ms: number): Promise => + new Promise((resolve) => setTimeout(resolve, ms)); + +describe('useSession Hook', () => { + beforeEach(() => { + jest.clearAllMocks(); + jest.spyOn(window, 'addEventListener').mockImplementation(jest.fn()); + jest.spyOn(window, 'removeEventListener').mockImplementation(jest.fn()); + Object.defineProperty(global, 'localStorage', { + value: { + clear: jest.fn(), + }, + writable: true, + }); + }); + + afterEach(() => { + jest.clearAllMocks(); + jest.useRealTimers(); + jest.restoreAllMocks(); + }); + + test('should handle visibility change to visible', async () => { + jest.useFakeTimers(); + + const { result } = renderHook(() => useSession(), { + wrapper: ({ children }: { children?: ReactNode }) => ( + + {children} + + ), + }); + + Object.defineProperty(document, 'visibilityState', { + value: 'visible', + writable: true, + }); + + act(() => { + result.current.startSession(); + }); + + // Simulate visibility change + act(() => { + document.dispatchEvent(new Event('visibilitychange')); + }); + + act(() => { + jest.advanceTimersByTime(15 * 60 * 1000); + }); + + await waitFor(() => { + expect(window.addEventListener).toHaveBeenCalledWith( + 'mousemove', + expect.any(Function), + ); + expect(window.addEventListener).toHaveBeenCalledWith( + 'keydown', + expect.any(Function), + ); + expect(toast.warning).toHaveBeenCalledWith('sessionWarning'); + }); + + jest.useRealTimers(); + }); + + test('should handle visibility change to hidden and ensure no warning appears in 15 minutes', async () => { + jest.useFakeTimers(); + + const { result } = renderHook(() => useSession(), { + wrapper: ({ children }: { children?: ReactNode }) => ( + + {children} + + ), + }); + + Object.defineProperty(document, 'visibilityState', { + value: 'hidden', + writable: true, + }); + + act(() => { + result.current.startSession(); + }); + + act(() => { + document.dispatchEvent(new Event('visibilitychange')); + }); + + act(() => { + jest.advanceTimersByTime(15 * 60 * 1000); + }); + + await waitFor(() => { + expect(window.removeEventListener).toHaveBeenCalledWith( + 'mousemove', + expect.any(Function), + ); + expect(window.removeEventListener).toHaveBeenCalledWith( + 'keydown', + expect.any(Function), + ); + expect(toast.warning).not.toHaveBeenCalled(); + }); + + jest.useRealTimers(); + }); + + test('should register event listeners on startSession', async () => { + const addEventListenerMock = jest.fn(); + const originalWindowAddEventListener = window.addEventListener; + const originalDocumentAddEventListener = document.addEventListener; + + window.addEventListener = addEventListenerMock; + document.addEventListener = addEventListenerMock; + + const { result } = renderHook(() => useSession(), { + wrapper: ({ children }: { children?: ReactNode }) => ( + + {children} + + ), + }); + + act(() => { + result.current.startSession(); + }); + + expect(addEventListenerMock).toHaveBeenCalledWith( + 'mousemove', + expect.any(Function), + ); + expect(addEventListenerMock).toHaveBeenCalledWith( + 'keydown', + expect.any(Function), + ); + expect(addEventListenerMock).toHaveBeenCalledWith( + 'visibilitychange', + expect.any(Function), + ); + + window.addEventListener = originalWindowAddEventListener; + document.addEventListener = originalDocumentAddEventListener; + }); + + test('should call handleLogout after session timeout', async () => { + jest.useFakeTimers(); + + const { result } = renderHook(() => useSession(), { + wrapper: ({ children }: { children?: ReactNode }) => ( + + {children} + + ), + }); + + act(() => { + result.current.startSession(); + }); + + act(() => { + jest.advanceTimersByTime(31 * 60 * 1000); + }); + + await waitFor(() => { + expect(global.localStorage.clear).toHaveBeenCalled(); + expect(toast.warning).toHaveBeenCalledTimes(2); + expect(toast.warning).toHaveBeenNthCalledWith(1, 'sessionWarning'); + expect(toast.warning).toHaveBeenNthCalledWith(2, 'sessionLogout', { + autoClose: false, + }); + }); + }); + + test('should show a warning toast before session expiration', async () => { + jest.useFakeTimers(); + + const { result } = renderHook(() => useSession(), { + wrapper: ({ children }: { children?: ReactNode }) => ( + + {children} + + ), + }); + + act(() => { + result.current.startSession(); + }); + + act(() => { + jest.advanceTimersByTime(15 * 60 * 1000); + }); + + await waitFor(() => + expect(toast.warning).toHaveBeenCalledWith('sessionWarning'), + ); + + jest.useRealTimers(); + }); + + test('should handle error when revoking token fails', async () => { + const consoleErrorMock = jest.spyOn(console, 'error').mockImplementation(); + + const errorMocks = [ + { + request: { + query: GET_COMMUNITY_SESSION_TIMEOUT_DATA, + }, + result: { + data: { + getCommunityData: { + timeout: 30, + }, + }, + }, + delay: 1000, + }, + { + request: { + query: REVOKE_REFRESH_TOKEN, + }, + error: new Error('Failed to revoke refresh token'), + }, + ]; + + const { result } = renderHook(() => useSession(), { + wrapper: ({ children }: { children?: ReactNode }) => ( + + {children} + + ), + }); + + act(() => { + result.current.startSession(); + result.current.handleLogout(); + }); + + await waitFor(() => + expect(consoleErrorMock).toHaveBeenCalledWith( + 'Error revoking refresh token:', + expect.any(Error), + ), + ); + + consoleErrorMock.mockRestore(); + }); + + test('should set session timeout based on fetched data', async () => { + jest.spyOn(global, 'setTimeout'); + + const { result } = renderHook(() => useSession(), { + wrapper: ({ children }: { children?: ReactNode }) => ( + + {children} + + ), + }); + + act(() => { + result.current.startSession(); + }); + + expect(global.setTimeout).toHaveBeenCalled(); + }); + + test('should call errorHandler on query error', async () => { + const errorMocks = [ + { + request: { + query: GET_COMMUNITY_SESSION_TIMEOUT_DATA, + }, + error: new Error('An error occurred'), + }, + ]; + + const { result } = renderHook(() => useSession(), { + wrapper: ({ children }: { children?: ReactNode }) => ( + + {children} + + ), + }); + + act(() => { + result.current.startSession(); + }); + + await waitFor(() => expect(errorHandler).toHaveBeenCalled()); + }); + //dfghjkjhgfds + + test('should remove event listeners on endSession', async () => { + const { result } = renderHook(() => useSession(), { + wrapper: ({ children }: { children?: ReactNode }) => ( + + {children} + + ), + }); + + // Mock the removeEventListener functions for both window and document + const removeEventListenerMock = jest.fn(); + + // Temporarily replace the real methods with the mock + const originalWindowRemoveEventListener = window.removeEventListener; + const originalDocumentRemoveEventListener = document.removeEventListener; + + window.removeEventListener = removeEventListenerMock; + document.removeEventListener = removeEventListenerMock; + + // await waitForNextUpdate(); + + act(() => { + result.current.startSession(); + }); + + act(() => { + result.current.endSession(); + }); + + // Test that event listeners were removed + expect(removeEventListenerMock).toHaveBeenCalledWith( + 'mousemove', + expect.any(Function), + ); + expect(removeEventListenerMock).toHaveBeenCalledWith( + 'keydown', + expect.any(Function), + ); + expect(removeEventListenerMock).toHaveBeenCalledWith( + 'visibilitychange', + expect.any(Function), + ); + + // Restore the original removeEventListener functions + window.removeEventListener = originalWindowRemoveEventListener; + document.removeEventListener = originalDocumentRemoveEventListener; + }); + + test('should call initialize timers when session is still active when the user returns to the tab', async () => { + jest.useFakeTimers(); + jest.spyOn(global, 'setTimeout').mockImplementation(jest.fn()); + + const { result } = renderHook(() => useSession(), { + wrapper: ({ children }) => ( + + {children} + + ), + }); + + jest.advanceTimersByTime(1000); + + // Set initial visibility state to visible + Object.defineProperty(document, 'visibilityState', { + value: 'visible', + writable: true, + }); + + // Start the session + act(() => { + result.current.startSession(); + jest.advanceTimersByTime(10 * 60 * 1000); // Fast-forward + }); + + // Simulate the user leaving the tab (set visibility to hidden) + Object.defineProperty(document, 'visibilityState', { + value: 'hidden', + writable: true, + }); + + act(() => { + document.dispatchEvent(new Event('visibilitychange')); + }); + + // Fast-forward time by more than the session timeout + act(() => { + jest.advanceTimersByTime(5 * 60 * 1000); // Fast-forward + }); + + // Simulate the user returning to the tab + Object.defineProperty(document, 'visibilityState', { + value: 'visible', + writable: true, + }); + + act(() => { + document.dispatchEvent(new Event('visibilitychange')); + }); + + jest.advanceTimersByTime(1000); + + expect(global.setTimeout).toHaveBeenCalled(); + + // Restore real timers + jest.useRealTimers(); + }); + + test('should call handleLogout when session expires due to inactivity away from tab', async () => { + jest.useFakeTimers(); // Use fake timers to control time + + const { result } = renderHook(() => useSession(), { + wrapper: ({ children }) => ( + + {children} + + ), + }); + + jest.advanceTimersByTime(1000); + + // Set initial visibility state to visible + Object.defineProperty(document, 'visibilityState', { + value: 'visible', + writable: true, + }); + + // Start the session + act(() => { + result.current.startSession(); + jest.advanceTimersByTime(10 * 60 * 1000); // Fast-forward + }); + + // Simulate the user leaving the tab (set visibility to hidden) + Object.defineProperty(document, 'visibilityState', { + value: 'hidden', + writable: true, + }); + + act(() => { + document.dispatchEvent(new Event('visibilitychange')); + }); + + // Fast-forward time by more than the session timeout + act(() => { + jest.advanceTimersByTime(32 * 60 * 1000); // Fast-forward by 32 minutes + }); + + // Simulate the user returning to the tab + Object.defineProperty(document, 'visibilityState', { + value: 'visible', + writable: true, + }); + + act(() => { + document.dispatchEvent(new Event('visibilitychange')); + }); + + jest.advanceTimersByTime(250); + + await waitFor(() => { + expect(global.localStorage.clear).toHaveBeenCalled(); + expect(toast.warning).toHaveBeenCalledWith('sessionLogout', { + autoClose: false, + }); + }); + + // Restore real timers + jest.useRealTimers(); + }); + + test('should handle logout and revoke token', async () => { + jest.useFakeTimers(); + + const { result } = renderHook(() => useSession(), { + wrapper: ({ children }: { children?: ReactNode }) => ( + + {children} + + ), + }); + + act(() => { + result.current.startSession(); + result.current.handleLogout(); + }); + + await waitFor(() => { + expect(global.localStorage.clear).toHaveBeenCalled(); + expect(toast.warning).toHaveBeenCalledWith('sessionLogout', { + autoClose: false, + }); + }); + + jest.useRealTimers(); + }); +}); diff --git a/src/utils/useSession.tsx b/src/utils/useSession.tsx new file mode 100644 index 0000000000..4279e7c850 --- /dev/null +++ b/src/utils/useSession.tsx @@ -0,0 +1,164 @@ +import { useMutation, useQuery } from '@apollo/client'; +import { REVOKE_REFRESH_TOKEN } from 'GraphQl/Mutations/mutations'; +import { GET_COMMUNITY_SESSION_TIMEOUT_DATA } from 'GraphQl/Queries/Queries'; +import { t } from 'i18next'; +import { useEffect, useState, useRef } from 'react'; +import { useTranslation } from 'react-i18next'; +import { useNavigate } from 'react-router-dom'; +import { toast } from 'react-toastify'; +import { errorHandler } from 'utils/errorHandler'; + +type UseSessionReturnType = { + startSession: () => void; + endSession: () => void; + handleLogout: () => void; + extendSession: () => void; //for when logged in already, simply extend session +}; + +/** + * Custom hook for managing user session timeouts in a React application. + * + * This hook handles: + * - Starting and ending the user session. + * - Displaying a warning toast at half of the session timeout duration. + * - Logging the user out and displaying a session expiration toast when the session times out. + * - Automatically resetting the timers when user activity is detected. + * - Pausing session timers when the tab is inactive and resuming them when it becomes active again. + * + * @returns UseSessionReturnType - An object with methods to start and end the session, and to handle logout. + */ +const useSession = (): UseSessionReturnType => { + const { t: tCommon } = useTranslation('common'); + + let startTime: number; + let timeoutDuration: number; + const [sessionTimeout, setSessionTimeout] = useState(30); + // const sessionTimeout = 30; + const sessionTimerRef = useRef(null); + const warningTimerRef = useRef(null); + const navigate = useNavigate(); + + const [revokeRefreshToken] = useMutation(REVOKE_REFRESH_TOKEN); + const { data, error: queryError } = useQuery( + GET_COMMUNITY_SESSION_TIMEOUT_DATA, + ); + + useEffect(() => { + if (queryError) { + errorHandler(t, queryError as Error); + } else { + const sessionTimeoutData = data?.getCommunityData; + if (sessionTimeoutData) { + setSessionTimeout(sessionTimeoutData.timeout); + } + } + }, [data, queryError]); + + const resetTimers = (): void => { + if (sessionTimerRef.current) clearTimeout(sessionTimerRef.current); + if (warningTimerRef.current) clearTimeout(warningTimerRef.current); + }; + + const endSession = (): void => { + resetTimers(); + window.removeEventListener('mousemove', extendSession); + window.removeEventListener('keydown', extendSession); + document.removeEventListener('visibilitychange', handleVisibilityChange); + }; + + const handleLogout = async (): Promise => { + try { + await revokeRefreshToken(); + } catch (error) { + console.error('Error revoking refresh token:', error); + // toast.error('Failed to revoke session. Please try again.'); + } + localStorage.clear(); + endSession(); + navigate('/'); + toast.warning(tCommon('sessionLogout'), { autoClose: false }); + }; + + const initializeTimers = ( + timeLeft?: number, + warningTimeLeft?: number, + ): void => { + const warningTime = warningTimeLeft ?? sessionTimeout / 2; + const sessionTimeoutInMilliseconds = + (timeLeft || sessionTimeout) * 60 * 1000; + const warningTimeInMilliseconds = warningTime * 60 * 1000; + + timeoutDuration = sessionTimeoutInMilliseconds; + startTime = Date.now(); + + warningTimerRef.current = setTimeout(() => { + toast.warning(tCommon('sessionWarning')); + }, warningTimeInMilliseconds); + + sessionTimerRef.current = setTimeout(async () => { + await handleLogout(); + }, sessionTimeoutInMilliseconds); + }; + + const extendSession = (): void => { + resetTimers(); + initializeTimers(); + }; + + const startSession = (): void => { + resetTimers(); + initializeTimers(); + window.removeEventListener('mousemove', extendSession); + window.removeEventListener('keydown', extendSession); + document.removeEventListener('visibilitychange', handleVisibilityChange); + window.addEventListener('mousemove', extendSession); + window.addEventListener('keydown', extendSession); + document.addEventListener('visibilitychange', handleVisibilityChange); + }; + + const handleVisibilityChange = async (): Promise => { + if (document.visibilityState === 'hidden') { + window.removeEventListener('mousemove', extendSession); + window.removeEventListener('keydown', extendSession); + resetTimers(); // Optionally reset timers to prevent them from running in the background + } else if (document.visibilityState === 'visible') { + window.removeEventListener('mousemove', extendSession); + window.removeEventListener('keydown', extendSession); // Ensure no duplicates + window.addEventListener('mousemove', extendSession); + window.addEventListener('keydown', extendSession); + + // Calculate remaining time now that the tab is active again + const elapsedTime = Date.now() - startTime; + const remainingTime = timeoutDuration - elapsedTime; + + const remainingSessionTime = Math.max(remainingTime, 0); // Ensures the remaining time is non-negative and measured in ms; + + if (remainingSessionTime > 0) { + // Calculate remaining warning time only if session time is positive + const remainingWarningTime = Math.max(remainingSessionTime / 2, 0); + initializeTimers( + remainingSessionTime / 60 / 1000, + remainingWarningTime / 60 / 1000, + ); + } else { + // Handle session expiration immediately if time has run out + await handleLogout(); + } + } + }; + + useEffect(() => { + return () => { + endSession(); + }; + }, []); + + return { + startSession, + endSession, + handleLogout, + extendSession, + }; +}; + +export default useSession; diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts new file mode 100644 index 0000000000..11f02fe2a0 --- /dev/null +++ b/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/tsconfig.json b/tsconfig.json index 57e5d011a4..0116d88a31 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,5 +1,6 @@ { "compilerOptions": { + "types": ["vite/client", "vite-plugin-svgr/client", "node"], "baseUrl": "src", "target": "es5", "lib": ["dom", "dom.iterable", "esnext"],