diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000..0ef78f43dc --- /dev/null +++ b/.dockerignore @@ -0,0 +1,25 @@ +node_modules +npm-debug.log +Dockerfile +.git +.gitignore +.env +.env.* +dist +coverage +.nyc_output +*.md +.github +tests +__tests__ +*.test.* +*.spec.* +# Development files +*.log +*.lock +.DS_Store +.idea +.vscode +# Build artifacts +build +out \ No newline at end of file diff --git a/.env.example b/.env.example index 399d5e6aab..de7cff92ec 100644 --- a/.env.example +++ b/.env.example @@ -24,8 +24,8 @@ REACT_APP_USE_RECAPTCHA= REACT_APP_RECAPTCHA_SITE_KEY= # has to be inserted in the env file to use plugins and other websocket based features. -REACT_APP_BACKEND_WEBSOCKET_URL=ws://localhost:4000/graphql +REACT_APP_BACKEND_WEBSOCKET_URL=ws://localhost:4000/graphql/ # If you want to logs Compiletime and Runtime error , warning and info write YES or if u want to # keep the console clean leave it blank -ALLOW_LOGS= \ No newline at end of file +ALLOW_LOGS= diff --git a/.eslintignore b/.eslintignore index 7e45de312a..ee98c5bdb0 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,2 +1,8 @@ # Contains the PDF file of the Tag as JSON string, thus does not need to be linted -src/components/CheckIn/tagTemplate.ts \ No newline at end of file +src/components/CheckIn/tagTemplate.ts +package.json +package-lock.json +tsconfig.json + +# Ignore the Docusaurus website subdirectory +docs/** \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json index 26470f7aab..de93fb465f 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -5,7 +5,6 @@ "es6": true }, - // Specify the rulesets from other ESLint Plugins tobe used "extends": [ "plugin:react/recommended", "eslint:recommended", @@ -28,7 +27,6 @@ "sourceType": "module" }, - // Specify the ESLint plugins tobe used "plugins": [ "react", "@typescript-eslint", @@ -55,6 +53,7 @@ "import/no-duplicates": "error", "tsdoc/syntax": "error", "@typescript-eslint/ban-ts-comment": "error", + "@typescript-eslint/no-unused-vars": "error", "@typescript-eslint/no-explicit-any": "error", "@typescript-eslint/no-inferrable-types": "error", "@typescript-eslint/no-non-null-asserted-optional-chain": "error", @@ -77,13 +76,13 @@ "camelcase": "off", "@typescript-eslint/naming-convention": [ "error", - // Interfaces must begin with Interface or TestInterface followed by a PascalCase name + { "selector": "interface", "format": ["PascalCase"], "prefix": ["Interface", "TestInterface"] }, - // Type Aliases must be in PascalCase + { "selector": ["typeAlias", "typeLike", "enum"], "format": ["PascalCase"] @@ -120,20 +119,17 @@ "format": null } ], - // Ensures that components are always written in PascalCase + "react/jsx-pascal-case": [ "error", { "allowAllCaps": false, "allowNamespace": false } ], - // Enforces whitespace around equal sign operators "react/jsx-equals-spacing": ["warn", "never"], "react/no-this-in-sfc": "error", - // All tests must need not have an assertion "jest/expect-expect": 0, - // Enforce Strictly functional components "react/no-unstable-nested-components": ["error", { "allowAsProps": true }], "react/function-component-definition": [ 0, @@ -142,10 +138,20 @@ "prettier/prettier": "error" }, - // Let ESLint use the react version in the package.json "settings": { "react": { "version": "detect" } - } + }, + "ignorePatterns": [ + "**/*.css", + "**/*.scss", + "**/*.less", + "**/*.json", + "**/*.svg", + "docs/docusaurus.config.ts", + "docs/sidebars.ts", + "docs/src/**", + "docs/blog/**" + ] } diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml index 2fc49726ff..81d68df4bd 100644 --- a/.github/dependabot.yaml +++ b/.github/dependabot.yaml @@ -7,12 +7,12 @@ updates: directory: "/" # Schedule automated updates to run weekly schedule: - interval: "weekly" + interval: "monthly" # Labels to apply to Dependabot PRs labels: - "dependencies" # Specify the target branch for PRs - target-branch: "develop" + target-branch: "develop-postgres" # Customize commit message prefix commit-message: - prefix: "chore(deps):" \ No newline at end of file + prefix: "chore(deps):" diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 9e3081d0ee..0748858133 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,3 +1,4 @@ + -**Did you add tests for your changes?** - - - **Snapshots/Videos:** @@ -44,10 +42,23 @@ Fixes # +## Checklist + +### CodeRabbit AI Review +- [ ] I have reviewed and addressed all critical issues flagged by CodeRabbit AI +- [ ] I have implemented or provided justification for each non-critical suggestion +- [ ] I have documented my reasoning in the PR comments where CodeRabbit AI suggestions were not implemented + +### Test Coverage +- [ ] I have written tests for all new changes/features +- [ ] I have verified that test coverage meets or exceeds 95% +- [ ] I have run the test suite locally and all tests pass + + **Other information** **Have you read the [contributing guide](https://github.com/PalisadoesFoundation/talawa-admin/blob/master/CONTRIBUTING.md)?** - + \ No newline at end of file diff --git a/.github/workflows/auto-label.json5 b/.github/workflows/auto-label.json5 new file mode 100644 index 0000000000..37929ea97b --- /dev/null +++ b/.github/workflows/auto-label.json5 @@ -0,0 +1,8 @@ +{ + "labelsSynonyms": { + "dependencies": ["dependabot", "dependency", "dependencies"], + "security": ["security"], + "ui/ux": ["layout", "screen", "design", "figma"] + }, + "defaultLabels": ["unapproved"], +} \ No newline at end of file diff --git a/.github/workflows/check-tsdoc.js b/.github/workflows/check-tsdoc.js index d5c3b33b90..0400f5a108 100644 --- a/.github/workflows/check-tsdoc.js +++ b/.github/workflows/check-tsdoc.js @@ -23,6 +23,7 @@ async function findTsxFiles(dir) { } else if ( filePath.endsWith('.tsx') && !filePath.endsWith('.test.tsx') && + !filePath.endsWith('.spec.tsx') && !filesToSkip.includes(path.relative(dir, filePath)) ) { results.push(filePath); diff --git a/.github/workflows/codeql-codescan.yml b/.github/workflows/codeql-codescan.yml index 6fa463001f..e018647d32 100644 --- a/.github/workflows/codeql-codescan.yml +++ b/.github/workflows/codeql-codescan.yml @@ -32,13 +32,13 @@ jobs: uses: actions/checkout@v4 - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} debug: true - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v3 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/issue.yml b/.github/workflows/issue.yml index 06da465ccf..05c703117e 100644 --- a/.github/workflows/issue.yml +++ b/.github/workflows/issue.yml @@ -18,12 +18,43 @@ jobs: name: Adding Issue Label runs-on: ubuntu-latest steps: - - uses: Renato66/auto-label@v2.3.0 + - uses: actions/checkout@v4 + with: + sparse-checkout: | + .github/workflows/auto-label.json5 + sparse-checkout-cone-mode: false + - uses: Renato66/auto-label@v3 with: repo-token: ${{ secrets.GITHUB_TOKEN }} - ignore-comments: true - default-labels: '["unapproved"]' - + - uses: actions/github-script@v7 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + script: | + const { owner, repo } = context.repo; + const issue_number = context.issue.number; + const apiParams = { + owner, + repo, + issue_number + }; + const labels = await github.rest.issues.listLabelsOnIssue(apiParams); + if(labels.data.reduce((a, c)=>a||["dependencies"].includes(c.name), false)) + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + labels: ["good first issue", "security"] + }); + else if(labels.data.reduce((a, c)=>a||["security", "ui/ux"].includes(c.name), false)) + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + labels: ["good first issue"] + }); + + Issue-Greeting: name: Greeting Message to User runs-on: ubuntu-latest diff --git a/.github/workflows/pull-request-target.yml b/.github/workflows/pull-request-target.yml index 2560a0dac9..082a5e965c 100644 --- a/.github/workflows/pull-request-target.yml +++ b/.github/workflows/pull-request-target.yml @@ -19,23 +19,26 @@ jobs: runs-on: ubuntu-latest steps: - name: Add the PR Review Policy - uses: thollander/actions-comment-pull-request@v2 + uses: thollander/actions-comment-pull-request@v3 with: - comment_tag: pr_review_policy + comment-tag: pr_review_policy message: | ## Our Pull Request Approval Process - - We have these basic policies to make the approval process smoother for our volunteer team. - + + Thanks for contributing! + ### Testing Your Code - - Please make sure your code passes all tests. Our test code coverage system will fail if these conditions occur: - - 1. The overall code coverage drops below the target threshold of the repository - 2. Any file in the pull request has code coverage levels below the repository threshold - 3. Merge conflicts - - The process helps maintain the overall reliability of the code base and is a prerequisite for getting your PR approved. Assigned reviewers regularly review the PR queue and tend to focus on PRs that are passing. + Remember, your PRs won't be reviewed until these criteria are met: + + 1. We don't merge PRs with poor code quality. + 1. Follow coding best practices such that CodeRabbit.ai approves your PR. + 1. We don't merge PRs with failed tests. + 1. When tests fail, click on the `Details` link to learn more. + 1. Write sufficient tests for your changes (CodeCov Patch Test). Your testing level must be better than the target threshold of the repository + 1. Tests may fail if you edit sensitive files. Ask to add the `ignore-sensitive-files-pr` label if the edits are necessary. + 1. We cannot merge PRs with conflicting files. These must be fixed. + + Our policies make our code better. ### Reviewers diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 75588cc4df..abd6775fb5 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -38,15 +38,18 @@ 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/components/TagActions/TagActionsMocks.ts src/utils/interfaces.ts src/screens/MemberDetail/MemberDetail.tsx - name: Get changed TypeScript files id: changed-files - uses: tj-actions/changed-files@v40 - + uses: tj-actions/changed-files@v45 - name: Check formatting if: steps.changed-files.outputs.only_changed != 'true' run: npm run format:check + + - name: Run formatting if check fails + if: failure() + run: npm run format:fix - name: Check for type errors if: steps.changed-files.outputs.only_changed != 'true' @@ -55,7 +58,7 @@ jobs: - name: Check for linting errors in modified files if: steps.changed-files.outputs.only_changed != 'true' env: - CHANGED_FILES: ${{ steps.changed_files.outputs.all_changed_files }} + CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }} run: npx eslint ${CHANGED_FILES} && python .github/workflows/eslint_disable_check.py - name: Check for TSDoc comments @@ -79,9 +82,9 @@ jobs: echo "Error: Source and Target Branches are the same. Please ensure they are different." exit 1 - Check-Unauthorized-Changes: - if: ${{ github.actor != 'dependabot[bot]' }} - name: Checks if no unauthorized files are changed + Check-Sensitive-Files: + if: ${{ github.actor != 'dependabot[bot]' && !contains(github.event.pull_request.labels.*.name, 'ignore-sensitive-files-pr') }} + name: Checks if sensitive files have been changed without authorization runs-on: ubuntu-latest steps: - name: Checkout code @@ -89,14 +92,17 @@ jobs: - name: Get Changed Unauthorized files id: changed-unauth-files - uses: tj-actions/changed-files@v40 + uses: tj-actions/changed-files@v45 with: files: | + .env* .github/** env.example .node-version .husky/** scripts/** + src/style/** + schema.graphql package.json tsconfig.json .gitignore @@ -104,6 +110,7 @@ jobs: .eslintignore .prettierrc .prettierignore + .nojekyll vite.config.ts docker-compose.yaml Dockerfile @@ -111,6 +118,20 @@ 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 + *.pem + *.key + *.cert + *.password + *.secret + *.credentials - name: List all changed unauthorized files if: steps.changed-unauth-files.outputs.any_changed == 'true' || steps.changed-unauth-files.outputs.any_deleted == 'true' @@ -120,6 +141,7 @@ jobs: for file in ${CHANGED_UNAUTH_FILES}; do echo "$file is unauthorized to change/delete" done + echo "To override this, apply the 'ignore-sensitive-files-pr' label" exit 1 Count-Changed-Files: @@ -132,7 +154,7 @@ jobs: - name: Get changed files id: changed-files - uses: tj-actions/changed-files@v40 + uses: tj-actions/changed-files@v45 - name: Echo number of changed files env: @@ -185,11 +207,30 @@ jobs: - name: Get changed TypeScript files id: changed-files - uses: tj-actions/changed-files@v40 + uses: tj-actions/changed-files@v45 - - name: Run tests + - name: Run Jest Tests if: steps.changed-files.outputs.only_changed != 'true' - run: npm run test -- --watchAll=false --coverage + env: + NODE_V8_COVERAGE: './coverage/jest' + run: | + npm run test -- --watchAll=false --coverage + + - name: Run Vitest Tests + if: steps.changed-files.outputs.only_changed != 'true' + env: + NODE_V8_COVERAGE: './coverage/vitest' + run: | + npm run test:vitest:coverage + + - name: Merge Coverage Reports + if: steps.changed-files.outputs.only_changed != 'true' + run: | + mkdir -p coverage + if ! npx lcov-result-merger 'coverage/*/lcov.info' > 'coverage/lcov.info'; then + echo "Failed to merge coverage reports" + exit 1 + fi - name: TypeScript compilation for changed files run: | @@ -198,25 +239,56 @@ jobs: npx tsc --noEmit "$file" fi done - + - name: Present and Upload coverage to Codecov as ${{env.CODECOV_UNIQUE_NAME}} uses: codecov/codecov-action@v4 with: token: ${{ secrets.CODECOV_TOKEN }} verbose: true + gcov_ignore: 'docs/' fail_ci_if_error: false + files: './coverage/lcov.info' name: '${{env.CODECOV_UNIQUE_NAME}}' - name: Test acceptable level of code coverage - uses: VeryGoodOpenSource/very_good_coverage@v2 + uses: VeryGoodOpenSource/very_good_coverage@v3 with: path: "./coverage/lcov.info" - min_coverage: 95.0 + min_coverage: 0.0 - Graphql-Inspector: - if: ${{ github.actor != 'dependabot[bot]' }} - name: Runs Introspection on the GitHub talawa-api repo on the schema.graphql file + # 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: + # - name: Checkout the Repository + # uses: actions/checkout@v4 + + # - name: Set up Node.js + # uses: actions/setup-node@v4 + # with: + # node-version: '22.x' + + # - name: resolve dependency + # run: npm install -g @graphql-inspector/cli + + # - name: Clone API Repository + # run: | + # # Retrieve the complete branch name directly from the GitHub context + # FULL_BRANCH_NAME=${{ github.base_ref }} + # echo "FULL_Branch_NAME: $FULL_BRANCH_NAME" + + # # Clone the specified repository using the extracted branch name + # git clone --branch $FULL_BRANCH_NAME https://github.com/PalisadoesFoundation/talawa-api && ls -a + + # - name: Validate Documents + # run: graphql-inspector validate './src/GraphQl/**/*.ts' './talawa-api/schema.graphql' + + Start-App-Without-Docker: + name: Check if Talawa Admin app starts (No Docker) runs-on: ubuntu-latest + needs: [Code-Quality-Checks, Test-Application] + if: github.actor != 'dependabot' steps: - name: Checkout the Repository uses: actions/checkout@v4 @@ -224,22 +296,136 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v4 with: - node-version: '22.x' + node-version: '20.x' - - name: resolve dependency - run: npm install -g @graphql-inspector/cli - - - name: Clone API Repository + - name: Install Dependencies + run: npm install + + - name: Build Production App + run: npm run build + + - name: Start Production App run: | - # Retrieve the complete branch name directly from the GitHub context - FULL_BRANCH_NAME=${{ github.base_ref }} - echo "FULL_Branch_NAME: $FULL_BRANCH_NAME" - - # Clone the specified repository using the extracted branch name - git clone --branch $FULL_BRANCH_NAME https://github.com/PalisadoesFoundation/talawa-api && ls -a + npm run preview & + echo $! > .pidfile_prod + - name: Check if Production App is running + run: | + timeout=120 + echo "Starting production health check with ${timeout}s timeout" + while ! nc -z localhost 4173 && [ $timeout -gt 0 ]; do + sleep 1 + timeout=$((timeout-1)) + if [ $((timeout % 10)) -eq 0 ]; then + echo "Still waiting for production app to start... ${timeout}s remaining" + fi + done + if [ $timeout -eq 0 ]; then + echo "Timeout waiting for production application to start" + exit 1 + fi + echo "Production app started successfully" + - name: Stop Production App + run: | + if [ -f .pidfile_prod ]; then + kill "$(cat .pidfile_prod)" + fi + - name: Start Development App + run: | + npm run serve & + echo $! > .pidfile_dev + - name: Check if Development App is running + run: | + timeout=120 + echo "Starting development health check with ${timeout}s timeout" + while ! nc -z localhost 4321 && [ $timeout -gt 0 ]; do + sleep 1 + timeout=$((timeout-1)) + if [ $((timeout % 10)) -eq 0 ]; then + echo "Still waiting for development app to start... ${timeout}s remaining" + fi + done + if [ $timeout -eq 0 ]; then + echo "Timeout waiting for development application to start" + exit 1 + fi + echo "Development app started successfully" + - name: Stop Development App + if: always() + run: | + if [ -f .pidfile_dev ]; then + kill "$(cat .pidfile_dev)" + fi + + Docker-Start-Check: + name: Check if Talawa Admin app starts in Docker + runs-on: ubuntu-latest + needs: [Code-Quality-Checks, Test-Application] + if: github.actor != 'dependabot' + steps: + - name: Checkout the Repository + uses: actions/checkout@v4 - - name: Validate Documents - run: graphql-inspector validate './src/GraphQl/**/*.ts' './talawa-api/schema.graphql' + - name: Set up Docker + uses: docker/setup-buildx-action@v3 + with: + driver-opts: | + image=moby/buildkit:latest + - name: Build Docker image + run: | + set -e + echo "Building Docker image..." + docker build -t talawa-admin-app . + echo "Docker image built successfully" + - name: Run Docker Container + run: | + set -e + echo "Started Docker container..." + docker run -d --name talawa-admin-app-container -p 4321:4321 talawa-admin-app + echo "Docker container started successfully" + - name: Check if Talawa Admin App is running + run: | + timeout="${HEALTH_CHECK_TIMEOUT:-120}" + echo "Starting health check with ${timeout}s timeout" + while ! nc -z localhost 4321 && [ $timeout -gt 0 ]; do + sleep 1 + timeout=$((timeout-1)) + if [ $((timeout % 10)) -eq 0 ]; then + echo "Still waiting for app to start... ${timeout}s remaining" + fi + done + if [ $timeout -eq 0 ]; then + echo "Timeout waiting for application to start" + echo "Container logs:" + docker logs talawa-admin-app-container + exit 1 + fi + echo "Port check passed, verifying health endpoint..." + - name: Stop Docker Container + if: always() + run: | + docker stop talawa-admin-app-container + docker rm talawa-admin-app-container + + Test-Docusaurus-Deployment: + name: Test Deployment to https://docs-admin.talawa.io + runs-on: ubuntu-latest + needs: [Docker-Start-Check, Start-App-Without-Docker] + # Run only if the develop-postgres branch and not dependabot + if: ${{ github.actor != 'dependabot[bot]' && github.event.pull_request.base.ref == 'develop-postgres' }} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: yarn + cache-dependency-path: 'docs/' + # Run Docusaurus in the ./docs directory + - name: Install dependencies + working-directory: ./docs + run: yarn install --frozen-lockfile + - name: Test building the website + working-directory: ./docs + run: yarn build Check-Target-Branch: if: ${{ github.actor != 'dependabot[bot]' }} @@ -247,8 +433,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check if the target branch is develop - if: github.event.pull_request.base.ref != 'develop' + if: github.event.pull_request.base.ref != 'develop-postgres' run: | - echo "Error: Pull request target branch must be 'develop'. Please refer PR_GUIDELINES.md" + echo "Error: Pull request target branch must be 'develop-postgres'. Please refer PR_GUIDELINES.md" exit 1 - diff --git a/.github/workflows/push-deploy-website.yml b/.github/workflows/push-deploy-website.yml new file mode 100644 index 0000000000..e03dab9840 --- /dev/null +++ b/.github/workflows/push-deploy-website.yml @@ -0,0 +1,57 @@ +############################################################################## +############################################################################## +# +# NOTE! +# +# Please read the README.md file in this directory that defines what should +# be placed in this file +# +############################################################################## +############################################################################## + +name: PUSH Workflow - Website Deployment + +on: + push: + branches: + - 'develop-postgres' + +env: + CODECOV_UNIQUE_NAME: CODECOV_UNIQUE_NAME-${{ github.run_id }}-${{ github.run_number }} + +jobs: + Deploy-Docusaurus: + name: Deploy https://docs-admin.talawa.io website + runs-on: ubuntu-latest + # Run only if the develop-postgres branch and not dependabot + if: ${{ github.actor != 'dependabot[bot]' }} + environment: + # This "name" has to be the repos' branch that contains + # the current active website. There must be an entry for + # the same branch in the PalisadoesFoundation's + # "Code and automation > Environments > gigithub-pages" + # menu. The branch "name" must match the branch in the + # "on.push.branches" section at the top of this file + name: develop-postgres + url: https://docs-admin.talawa.io + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: yarn + cache-dependency-path: 'docs/' + - uses: webfactory/ssh-agent@v0.9.0 + with: + ssh-private-key: ${{ secrets.DEPLOY_GITHUB_PAGES }} + - name: Deploy to GitHub Pages + env: + USE_SSH: true + GIT_USER: git + working-directory: ./docs + run: | + git config --global user.email "actions@github.com" + git config --global user.name "gh-actions" + yarn install --frozen-lockfile + yarn deploy + diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 950d063fac..7f7328b38c 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -9,7 +9,7 @@ ############################################################################## ############################################################################## -name: push workflow +name: PUSH Workflow - All Branches on: push: @@ -53,10 +53,10 @@ jobs: run: npm install - run: npm run test -- --watchAll=false --coverage - name: Present and upload coverage to Codecov as ${{env.CODECOV_UNIQUE_NAME}} - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} verbose: true + gcov_ignore: 'docs/' fail_ci_if_error: false name: '${{env.CODECOV_UNIQUE_NAME}}' - diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 24667f8e06..3430d52ec8 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -25,7 +25,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/stale@v8 + - uses: actions/stale@v9 with: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-issue-message: 'This issue did not get any activity in the past 10 days and will be closed in 180 days if no update occurs. Please check if the develop branch has fixed it and report again or close the issue.' @@ -40,4 +40,4 @@ jobs: exempt-all-milestones: true exempt-pr-labels: 'wip' exempt-issue-labels: 'wip' - operations-per-run: 30 + operations-per-run: 50 diff --git a/.husky/pre-commit b/.husky/pre-commit index c9c109cceb..77ecddae25 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,7 +1,7 @@ #!/usr/bin/env sh . "$(dirname -- "$0")/_/husky.sh" -# npm run format:fix +npm run format:fix # npm run lint:fix npm run lint-staged npm run typecheck diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000..6b13a712b7 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,15 @@ +FROM node:20.10.0 AS build + +WORKDIR /usr/src/app + +COPY package*.json ./ + +RUN npm install + +COPY . . + +RUN npm run build + +EXPOSE 4321 + +CMD ["npm", "run", "serve"] \ No newline at end of file diff --git a/INSTALLATION.md b/INSTALLATION.md index 05ede15d0c..3c09f69e33 100644 --- a/INSTALLATION.md +++ b/INSTALLATION.md @@ -13,24 +13,9 @@ This document provides instructions on how to set up and start a running instanc - [Install node.js](#install-nodejs) - [Install TypeScript](#install-typescript) - [Install Required Packages](#install-required-packages) -- [Configuration](#configuration) - - [Creating .env file](#creating-env-file) - - [Setting up PORT in .env file](#setting-up-port-in-env-file) - - [Setting up REACT_APP_TALAWA_URL in .env file](#setting-up-react_app_talawa_url-in-env-file) - - [Setting up REACT_APP_RECAPTCHA_SITE_KEY in .env file](#setting-up-react_app_recaptcha_site_key-in-env-file) - - [Setting up Compiletime and Runtime logs](#setting-up-compiletime-and-runtime-logs) -- [Post Configuration Steps](#post-configuration-steps) - - [Running Talawa-Admin](#running-talawa-admin) - - [Accessing Talawa-Admin](#accessing-talawa-admin) - - [Talawa-Admin Registration](#talawa-admin-registration) - - [Talawa-Admin Login](#talawa-admin-login) -- [Testing](#testing) - - [Running tests](#running-tests) - - [Debugging tests](#debugging-tests) - - [Linting code files](#linting-code-files) - - [Husky for Git Hooks](#husky-for-git-hooks) - - [pre-commit hook](#pre-commit-hook) - - [post-merge hook](#post-merge-hook) +- [Installation using Docker](#installation-using-docker) + - [Prerequisites](#prerequisites-1) + - [Development Setup](#development-setup) @@ -65,31 +50,34 @@ First you need a local copy of `talawa-admin`. Run the following command in the 1. On your computer, navigate to the folder where you want to setup the repository. 2. Open a `cmd` (Windows) or `terminal` (Linux or MacOS) session in this folder. - 1. An easy way to do this is to right-click and choose appropriate option based on your OS. + 1. An easy way to do this is to right-click and choose appropriate option based on your OS. 3. **For Our Open Source Contributor Software Developers:** - 1. Next, we'll fork and clone the `talawa-admin` repository. - 1. In your web browser, navigate to [https://github.com/PalisadoesFoundation/talawa-admin/](https://github.com/PalisadoesFoundation/talawa-admin/) and click on the `fork` button. It is placed on the right corner opposite the repository name `PalisadoesFoundation/talawa-admin`. - ![Image with fork](public/markdown/images/install1.png) + 1. Next, we'll fork and clone the `talawa-admin` repository. + 1. In your web browser, navigate to [https://github.com/PalisadoesFoundation/talawa-admin/](https://github.com/PalisadoesFoundation/talawa-admin/) and click on the `fork` button. It is placed on the right corner opposite the repository name `PalisadoesFoundation/talawa-admin`. - 2. You should now see `talawa-admin` under your repositories. It will be marked as forked from `PalisadoesFoundation/talawa-admin` + ![Image with fork](public/markdown/images/install1.png) - ![Image of user's clone](public/markdown/images/install2.png) + 1. You should now see `talawa-admin` under your repositories. It will be marked as forked from `PalisadoesFoundation/talawa-admin` + + ![Image of user's clone](public/markdown/images/install2.png) + + 1. Clone the repository to your local computer (replacing the values in `{{}}`): + ```bash + $ git clone https://github.com/{{YOUR GITHUB USERNAME}}/talawa-admin.git + cd talawa-admin + git checkout develop + ``` + - **Note:** Make sure to check out the `develop` branch + 1. You now have a local copy of the code files. For more detailed instructions on contributing code, and managing the versions of this repository with `git`, checkout our [CONTRIBUTING.md](./CONTRIBUTING.md) file. - 3. Clone the repository to your local computer (replacing the values in `{{}}`): - ```bash - $ git clone https://github.com/{{YOUR GITHUB USERNAME}}/talawa-admin.git - cd talawa-admin - git checkout develop - ``` - - **Note:** Make sure to check out the `develop` branch - 4. You now have a local copy of the code files. For more detailed instructions on contributing code, and managing the versions of this repository with `git`, checkout our [CONTRIBUTING.md](./CONTRIBUTING.md) file. 4. **Talawa Administrators:** - 1. Clone the repository to your local computer using this command: - ```bash - $ git clone https://github.com/PalisadoesFoundation/talawa-admin.git - ``` + 1. Clone the repository to your local computer using this command: + + ```bash + $ git clone https://github.com/PalisadoesFoundation/talawa-admin.git + ``` ## Install node.js @@ -98,26 +86,26 @@ Best way to install and manage `node.js` is making use of node version managers. Follow these steps to install the `node.js` packages in Windows, Linux and MacOS. 1. For Windows: - 1. first install `node.js` from their website at https://nodejs.org - 1. When installing, don't click the option to install the `necessary tools`. These are not needed in our case. - 2. then install [fnm](https://github.com/Schniz/fnm). Please read all the steps in this section first. - 1. All the commands listed on this page will need to be run in a Windows terminal session in the `talawa-admin` directory. - 2. Install `fnm` using the `winget` option listed on the page. - 3. Setup `fnm` to automatically set the version of `node.js` to the version required for the repository using these steps: - 1. First, refer to the `fnm` web page's section on `Shell Setup` recommendations. - 2. Open a `Windows PowerShell` terminal window - 3. Run the recommended `Windows PowerShell` command to open `notepad`. - 4. Paste the recommended string into `notepad` - 5. Save the document. - 6. Exit `notepad` - 7. Exit PowerShell - 8. This will ensure that you are always using the correct version of `node.js` + 1. first install `node.js` from their website at https://nodejs.org + 1. When installing, don't click the option to install the `necessary tools`. These are not needed in our case. + 2. then install [fnm](https://github.com/Schniz/fnm). Please read all the steps in this section first. + 1. All the commands listed on this page will need to be run in a Windows terminal session in the `talawa-admin` directory. + 2. Install `fnm` using the `winget` option listed on the page. + 3. Setup `fnm` to automatically set the version of `node.js` to the version required for the repository using these steps: + 1. First, refer to the `fnm` web page's section on `Shell Setup` recommendations. + 2. Open a `Windows PowerShell` terminal window + 3. Run the recommended `Windows PowerShell` command to open `notepad`. + 4. Paste the recommended string into `notepad` + 5. Save the document. + 6. Exit `notepad` + 7. Exit PowerShell + 8. This will ensure that you are always using the correct version of `node.js` 2. For Linux and MacOS, use the terminal window. 1. install `node.js` 2. then install `fnm` - 1. Refer to the installation page's section on the `Shell Setup` recommendations. - 2. Run the respective recommended commands to setup your node environment - 3. This will ensure that you are always using the correct version of `node.js` + 1. Refer to the installation page's section on the `Shell Setup` recommendations. + 2. Run the respective recommended commands to setup your node environment + 3. This will ensure that you are always using the correct version of `node.js` ## Install TypeScript @@ -141,15 +129,47 @@ npm install The prerequisites are now installed. The next step will be to get the app up and running. +# Installation using Docker + +## Prerequisites + +1. Install Docker on your system: + - [Docker Desktop for Windows/Mac](https://www.docker.com/products/docker-desktop) + - [Docker Engine for Linux](https://docs.docker.com/engine/install/) + +### Development Setup + +If you prefer to use Docker, you can install the app using the following command: + +1. Create a `.env` file as described in the Configuration section + +2. Build the Docker Image: + +Run the following command to build the Docker image: + +````bash +docker build -t talawa-admin . +```bash + +3. Run the Docker container: + +After the build is complete, run the Docker container using this command: + +```bash +docker run -p 4321:4321 talawa-admin +```bash + +The application will be accessible at `http://localhost:4321` + # Configuration It's important to configure Talawa-Admin. Here's how to do it. You can use our interactive setup script for the configuration. Use the following command for the same. -``` +```bash npm run setup -``` +```bash All the options in "setup" can be done manually as well and here's how to do it. - [Creating .env file](#creating-env-file) @@ -157,20 +177,23 @@ All the options in "setup" can be done manually as well and here's how to do it. A file named .env is required in the root directory of talawa-admin for storing environment variables used at runtime. It is not a part of the repo and you will have to create it. For a sample of `.env` file there is a file named `.env.example` in the root directory. Create a new `.env` file by copying the contents of the `.env.example` into `.env` file. Use this command: -``` +```` + cp .env.example .env + ``` This `.env` file must be populated with the following environment variables for `talawa-admin` to work: -| Variable | Description | -| ---------------------------- | ------------------------------------------------- | -| PORT | Custom port for Talawa-Admin development purposes | -| REACT_APP_TALAWA_URL | URL endpoint for talawa-api graphql service | -| REACT_APP_USE_RECAPTCHA | Whether you want to use reCAPTCHA or not | -| REACT_APP_RECAPTCHA_SITE_KEY | Site key for authentication using reCAPTCHA | +| Variable | Description | +| ------------------------------- | ------------------------------------------------- | +| PORT | Custom port for Talawa-Admin development purposes | +| REACT_APP_TALAWA_URL | URL endpoint for talawa-api graphql service | +| REACT_APP_BACKEND_WEBSOCKET_URL | URL endpoint for websocket end point | +| REACT_APP_USE_RECAPTCHA | Whether you want to use reCAPTCHA or not | +| REACT_APP_RECAPTCHA_SITE_KEY | Site key for authentication using reCAPTCHA | -Follow the instructions from the sections [Setting up PORT in .env file](#setting-up-port-in-env-file), [Setting up REACT_APP_TALAWA_URL in .env file](#setting-up-REACT_APP_TALAWA_URL-in-env-file), [Setting up REACT_APP_RECAPTCHA_SITE_KEY in .env file](#setting-up-REACT_APP_RECAPTCHA_SITE_KEY-in-env-file) and [Setting up Compiletime and Runtime logs](#setting-up-compiletime-and-runtime-logs) to set up these environment variables. +Follow the instructions from the sections [Setting up PORT in .env file](#setting-up-port-in-env-file), [Setting up REACT_APP_TALAWA_URL in .env file](#setting-up-REACT_APP_TALAWA_URL-in-env-file), [Setting up REACT_APP_BACKEND_WEBSOCKET_URL in .env file](#setting-up-react_app_backend_websocket_url-in-env-file), [Setting up REACT_APP_RECAPTCHA_SITE_KEY in .env file](#setting-up-REACT_APP_RECAPTCHA_SITE_KEY-in-env-file) and [Setting up Compiletime and Runtime logs](#setting-up-compiletime-and-runtime-logs) to set up these environment variables. ## Setting up PORT in .env file @@ -181,22 +204,54 @@ Add a custom port number for Talawa-Admin development purposes to the variable n Add the endpoint for accessing talawa-api graphql service to the variable named `REACT_APP_TALAWA_URL` in the `.env` file. ``` + REACT_APP_TALAWA_URL="http://API-IP-ADRESS:4000/graphql/" + ``` If you are a software developer working on your local system, then the URL would be: ``` + REACT_APP_TALAWA_URL="http://localhost:4000/graphql/" + ``` If you are trying to access Talawa Admin from a remote host with the API URL containing "localhost", You will have to change the API URL to ``` + REACT_APP_TALAWA_URL="http://YOUR-REMOTE-ADDRESS:4000/graphql/" + +``` + +## Setting up REACT_APP_BACKEND_WEBSOCKET_URL in .env file + +The endpoint for accessing talawa-api WebSocket graphql service for handling subscriptions is automatically added to the variable named `REACT_APP_BACKEND_WEBSOCKET_URL` in the `.env` file. + +``` + +REACT_APP_BACKEND_WEBSOCKET_URL="ws://API-IP-ADRESS:4000/graphql/" + +``` + +If you are a software developer working on your local system, then the URL would be: + +``` + +REACT_APP_BACKEND_WEBSOCKET_URL="ws://localhost:4000/graphql/" + +``` + +If you are trying to access Talawa Admin from a remote host with the API URL containing "localhost", You will have to change the API URL to + +``` + +REACT_APP_BACKEND_WEBSOCKET_URL="ws://YOUR-REMOTE-ADDRESS:4000/graphql/" + ``` -For additional details, please refer the `How to Access the Talawa-API URL` section in the INSTALLATION.md file found in the [Talawa-API repo](https://github.com/PalisadoesFoundation/talawa-api). +For additional details, please refer the `How to Access the Talawa-API URL` section in the INSTALLATION.md file found in the [Talawa-API repo](https://github.com/PalisadoesFoundation/talawa-api). ## Setting up REACT_APP_RECAPTCHA_SITE_KEY in .env file @@ -213,7 +268,9 @@ If you want to setup Google reCAPTCHA now, you may refer to the `RECAPTCHA` sect Copy/paste this `reCAPTCHA site key` to the variable named `REACT_APP_RECAPTCHA_SITE_KEY` in `.env` file. ``` + REACT_APP_RECAPTCHA_SITE_KEY="this_is_the_recaptcha_key" + ``` ## Setting up Compiletime and Runtime logs @@ -229,7 +286,9 @@ It's now time to start Talawa-Admin and get it running Run the following command to start `talawa-admin` development server: ``` + npm run serve + ``` ## Accessing Talawa-Admin @@ -237,13 +296,17 @@ npm run serve By default `talawa-admin` runs on port `4321` on your system's localhost. It is available on the following endpoint: ``` + http://localhost:4321/ + ``` If you have specified a custom port number in your `.env` file, Talawa-Admin will run on the following endpoint: ``` + http://localhost:${{customPort}}/ + ``` Replace `${{customPort}}` with the actual custom port number you have configured in your `.env` file. @@ -265,7 +328,9 @@ It is important to test our code. If you are a contributor, please follow these You can run the tests for `talawa-admin` using this command: ``` + npm run test + ``` ## Debugging tests @@ -273,8 +338,10 @@ npm run test You can see the output of failing tests in broswer by running `jest-preview` package before running your tests ``` + npm run jest-preview npm run test + ``` You don't need to re-run the `npm run jest-preview` command each time, simply run the `npm run test` command if the Jest Preview server is already running in the background, it'll automatically detect any failing tests and show the preview at `http://localhost:3336` as shown in this screenshot - @@ -286,7 +353,9 @@ You don't need to re-run the `npm run jest-preview` command each time, simply ru You can lint your code files using this command: ``` + npm run lint:fix + ``` ## Husky for Git Hooks @@ -310,3 +379,4 @@ If you don't want this hook to run, you can manually opt out of this using the ` git pull --no-verify
+``` diff --git a/README.md b/README.md index cbade9e407..911ba11453 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Talawa Admin -[💬 Join the community on Slack](https://github.com/PalisadoesFoundation/) +💬 Join the community on Slack from our [Palisadoes Foundation GitHub Home Page](https://github.com/PalisadoesFoundation) ![talawa-logo-lite-200x200](https://github.com/PalisadoesFoundation/talawa-admin/assets/16875803/26291ec5-d3c1-4135-8bc7-80885dff613d) diff --git a/config/vite.config.ts b/config/vite.config.ts index 71ce6c6f47..28cd47ae5a 100644 --- a/config/vite.config.ts +++ b/config/vite.config.ts @@ -23,8 +23,9 @@ export default defineConfig({ ], server: { // this ensures that the browser opens upon server start - open: true, - // this sets a default port to 3000 + open: false, + host: '0.0.0.0', + // this sets a default port to 4321 port: 4321, }, }); diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000000..7dd4990993 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,22 @@ +# Dependencies +/node_modules + +# Production +/build + +# Generated files +.docusaurus +.cache-loader +.package-lock.json +package-lock.json + +# Misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/docs/CNAME b/docs/CNAME new file mode 100644 index 0000000000..2594cfef31 --- /dev/null +++ b/docs/CNAME @@ -0,0 +1 @@ +docs-admin.talawa.io diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000000..4553d05f51 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,176 @@ +# Talawa-Admin Documentation Website + +[![N|Solid](static/img/markdown/misc/logo.png)](https://github.com/PalisadoesFoundation/docs-admin) + +# Installation + +This document provides instructions on how to set up and start a running instance of docs-admin website on your local system. The instructions are written to be followed in sequence so make sure to go through each of them step by step without skipping any sections. + +# Table of Contents + + + +- [Developer-Docs Installation](#docs-admin-installation) +- [Table of Contents](#table-of-contents) +- [Prerequisites for Developers](#prerequisites-for-developers) + - [Install node.js](#install-nodejs) + - [Install the Required Packages](#install-the-required-packages) + - [Install Yarn on Windows Using NPM](#install-yarn-on-windows-using-npm) + - [Install Yarn on Windows Using msi File](#install-yarn-on-windows-using-msi-file) + - [Install Yarn on macOS Using NPM](#install-yarn-on-macos-using-npm) + - [Install Yarn on macOS Using Homebrew](#install-yarn-on-macos-using-homebrew) + - [Install Yarn on Linux Using NPM](#install-yarn-on-linux-using-npm) +- [Running the Development Server](#running-the-development-server) +- [Building Static HTML Pages](#building-static-html-pages) + +# Prerequisites for Developers + +The contents of the `docs-admin` repo is used to automatically create [the Talawa-Admin Documentation website](https://docs-admin.talawa.io/). The automation uses [Docusaurus](https://docusaurus.io/docs/), a modern static website generator. + +We recommend that you follow these steps before beginning development work in this repository. + +## Install the Required Packages + +For the package installation, use only the `yarn` package as `npm` will throw an error. Only `npm` use case here would be to install the `yarn` package. Visit the [Docusaurus installation web page](https://docusaurus.io/docs/installation) if you have any difficulties with the steps below. + +The steps are simple: + +1. If you have previously installed yarn on your local device run the following command to confirm + +```terminal +$ yarn -version +``` + +2. If you don't have yarn installed, follow these steps: + +**Note:** Please bear in mind that to install docusaurus in your system, a Node.js version 16.14 or above (which can be checked by running node -v) is required. Other requirements that pertains to the installation of docusaurus can be found [here](https://docusaurus.io/docs/installation) + +```console +$ git clone https://github.com/PalisadoesFoundation/docs-admin.git +$ cd docs-admin +$ yarn add docusaurus +``` + +### Install Yarn on Windows Using NPM + +NPM (Node Package Manager) is a package manager included with the Node.js installation. It is used for developing and sharing JavaScript code, but it also provides another method of installing Yarn + +1. [Download the Node Windows installer](https://nodejs.org/en/download/) +1. After choosing the path, double-click to install. Then give access to run the application +1. Install Yarn by running the following command + +```terminal +$ npm install --global yarn +``` + +4. Check Yarn installation + +```terminal +$ yarn -version +``` + +### Install Yarn on Windows Using msi File + +Here’s how to install the Yarn package manager on Windows + +1. [Download the Yarn Windows installer](https://classic.yarnpkg.com/en/docs/install#windows-stable) +1. After choosing the path, double-click to install. Then give access to run the application + +1. Check Yarn installation + +```terminal +$ yarn -version +``` + +### Install Yarn on macOS Using NPM + +The .pkg installer can be used to install Yarn on macOS. Using the .pkg installer also helps resolve dependencies since it does not require a command line to install Node.js + +1. [Click on the macOS Installer option to download the .pkg installer](https://nodejs.org/en/download/) +2. Run the Node.js installer +3. Verify Node.js Installation by running the following command in your terminal + +```terminal +$ node -v +$ npm -v +``` + +4. Run the following command to install Yarn + +```terminal +$ sudo npm install --global yarn +``` + +5. Verify Yarn Installation + +```terminal +$ yarn --version +``` + +### Install Yarn on macOS Using Homebrew + +One of the easiest way to install Yarn on macOS is to use the command line installer + +1. Install Yarn by running the given command in your terminal + +```terminal +$ brew install yarn +``` + +### Install Yarn on Linux Using NPM + +Installing Yarn on Linux through NPM can be done via command line installer, this doesn't automatically install Node.js + +1. Run the following command in your terminal to install Node and NPM respectively. [Confirm your Linux distro and it's command prompt](https://classic.yarnpkg.com/lang/en/docs/install/#debian-stable) + +```terminal +$ sudo apt install nodejs +$ sudo apt install npm +``` + +2. Verify installation + +```terminal +$ node -v +$ npm -v +``` + +3. Install Yarn with the following command + +```terminal +npm install --global yarn +``` + +Finally, after installing yarn and confirming that it is installed in your computer, run the command below to install the packages + +```terminal +$ yarn install +``` + +# Running the Development Server + +To preview your changes as you edit the files, you can run a local development server that will serve your website and it will reflect the latest changes. + +The command to run the server is: + +```console +$ yarn run start +OR +$ yarn start +``` + +By default, a browser window will open at http://localhost:3000. + +This command starts a local development server and open up a browser window. Most changes are reflected live without having to restart the server. + +# Building Static HTML Pages + +**In most cases is unnecessary**. Running the `development server` will be sufficient. + +If you need to generate static HTML pages (unlikely), then follow these steps. + +```console +$ yarn run build +``` + +This command generates static content into the `/build` directory and can be served using any static contents hosting service. \ No newline at end of file diff --git a/docs/blog/2019-05-28-first-blog-post.md b/docs/blog/2019-05-28-first-blog-post.md new file mode 100644 index 0000000000..d3032efb35 --- /dev/null +++ b/docs/blog/2019-05-28-first-blog-post.md @@ -0,0 +1,12 @@ +--- +slug: first-blog-post +title: First Blog Post +authors: [slorber, yangshun] +tags: [hola, docusaurus] +--- + +Lorem ipsum dolor sit amet... + + + +...consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet diff --git a/docs/blog/2019-05-29-long-blog-post.md b/docs/blog/2019-05-29-long-blog-post.md new file mode 100644 index 0000000000..eb4435de59 --- /dev/null +++ b/docs/blog/2019-05-29-long-blog-post.md @@ -0,0 +1,44 @@ +--- +slug: long-blog-post +title: Long Blog Post +authors: yangshun +tags: [hello, docusaurus] +--- + +This is the summary of a very long blog post, + +Use a `` comment to limit blog post size in the list view. + + + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet diff --git a/docs/blog/2021-08-01-mdx-blog-post.mdx b/docs/blog/2021-08-01-mdx-blog-post.mdx new file mode 100644 index 0000000000..0c4b4a48b9 --- /dev/null +++ b/docs/blog/2021-08-01-mdx-blog-post.mdx @@ -0,0 +1,24 @@ +--- +slug: mdx-blog-post +title: MDX Blog Post +authors: [slorber] +tags: [docusaurus] +--- + +Blog posts support [Docusaurus Markdown features](https://docusaurus.io/docs/markdown-features), such as [MDX](https://mdxjs.com/). + +:::tip + +Use the power of React to create interactive blog posts. + +::: + +{/* truncate */} + +For example, use JSX to create an interactive button: + +```js + +``` + + diff --git a/docs/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg b/docs/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg new file mode 100644 index 0000000000..11bda09284 Binary files /dev/null and b/docs/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg differ diff --git a/docs/blog/2021-08-26-welcome/index.md b/docs/blog/2021-08-26-welcome/index.md new file mode 100644 index 0000000000..349ea075f5 --- /dev/null +++ b/docs/blog/2021-08-26-welcome/index.md @@ -0,0 +1,29 @@ +--- +slug: welcome +title: Welcome +authors: [slorber, yangshun] +tags: [facebook, hello, docusaurus] +--- + +[Docusaurus blogging features](https://docusaurus.io/docs/blog) are powered by the [blog plugin](https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-content-blog). + +Here are a few tips you might find useful. + + + +Simply add Markdown files (or folders) to the `blog` directory. + +Regular blog authors can be added to `authors.yml`. + +The blog post date can be extracted from filenames, such as: + +- `2019-05-30-welcome.md` +- `2019-05-30-welcome/index.md` + +A blog post folder can be convenient to co-locate blog post images: + +![Docusaurus Plushie](./docusaurus-plushie-banner.jpeg) + +The blog supports tags as well! + +**And if you don't want a blog**: just delete this directory, and use `blog: false` in your Docusaurus config. diff --git a/docs/blog/authors.yml b/docs/blog/authors.yml new file mode 100644 index 0000000000..8bfa5c7c4b --- /dev/null +++ b/docs/blog/authors.yml @@ -0,0 +1,23 @@ +yangshun: + name: Yangshun Tay + title: Front End Engineer @ Facebook + url: https://github.com/yangshun + image_url: https://github.com/yangshun.png + page: true + socials: + x: yangshunz + github: yangshun + +slorber: + name: Sébastien Lorber + title: Docusaurus maintainer + url: https://sebastienlorber.com + image_url: https://github.com/slorber.png + page: + # customize the url of the author page at /blog/authors/ + permalink: '/all-sebastien-lorber-articles' + socials: + x: sebastienlorber + linkedin: sebastienlorber + github: slorber + newsletter: https://thisweekinreact.com diff --git a/docs/blog/tags.yml b/docs/blog/tags.yml new file mode 100644 index 0000000000..bfaa778fbd --- /dev/null +++ b/docs/blog/tags.yml @@ -0,0 +1,19 @@ +facebook: + label: Facebook + permalink: /facebook + description: Facebook tag description + +hello: + label: Hello + permalink: /hello + description: Hello tag description + +docusaurus: + label: Docusaurus + permalink: /docusaurus + description: Docusaurus tag description + +hola: + label: Hola + permalink: /hola + description: Hola tag description diff --git a/docs/docs/intro.md b/docs/docs/intro.md new file mode 100644 index 0000000000..45e8604c8b --- /dev/null +++ b/docs/docs/intro.md @@ -0,0 +1,47 @@ +--- +sidebar_position: 1 +--- + +# Tutorial Intro + +Let's discover **Docusaurus in less than 5 minutes**. + +## Getting Started + +Get started by **creating a new site**. + +Or **try Docusaurus immediately** with **[docusaurus.new](https://docusaurus.new)**. + +### What you'll need + +- [Node.js](https://nodejs.org/en/download/) version 18.0 or above: + - When installing Node.js, you are recommended to check all checkboxes related to dependencies. + +## Generate a new site + +Generate a new Docusaurus site using the **classic template**. + +The classic template will automatically be added to your project after you run the command: + +```bash +npm init docusaurus@latest my-website classic +``` + +You can type this command into Command Prompt, Powershell, Terminal, or any other integrated terminal of your code editor. + +The command also installs all necessary dependencies you need to run Docusaurus. + +## Start your site + +Run the development server: + +```bash +cd my-website +npm run start +``` + +The `cd` command changes the directory you're working with. In order to work with your newly created Docusaurus site, you'll need to navigate the terminal there. + +The `npm run start` command builds your website locally and serves it through a development server, ready for you to view at http://localhost:3000/. + +Open `docs/intro.md` (this page) and edit some lines: the site **reloads automatically** and displays your changes. diff --git a/docs/docs/tutorial-basics/_category_.json b/docs/docs/tutorial-basics/_category_.json new file mode 100644 index 0000000000..2e6db55b1e --- /dev/null +++ b/docs/docs/tutorial-basics/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "Tutorial - Basics", + "position": 2, + "link": { + "type": "generated-index", + "description": "5 minutes to learn the most important Docusaurus concepts." + } +} diff --git a/docs/docs/tutorial-basics/congratulations.md b/docs/docs/tutorial-basics/congratulations.md new file mode 100644 index 0000000000..04771a00b7 --- /dev/null +++ b/docs/docs/tutorial-basics/congratulations.md @@ -0,0 +1,23 @@ +--- +sidebar_position: 6 +--- + +# Congratulations! + +You have just learned the **basics of Docusaurus** and made some changes to the **initial template**. + +Docusaurus has **much more to offer**! + +Have **5 more minutes**? Take a look at **[versioning](../tutorial-extras/manage-docs-versions.md)** and **[i18n](../tutorial-extras/translate-your-site.md)**. + +Anything **unclear** or **buggy** in this tutorial? [Please report it!](https://github.com/facebook/docusaurus/discussions/4610) + +## What's next? + +- Read the [official documentation](https://docusaurus.io/) +- Modify your site configuration with [`docusaurus.config.js`](https://docusaurus.io/docs/api/docusaurus-config) +- Add navbar and footer items with [`themeConfig`](https://docusaurus.io/docs/api/themes/configuration) +- Add a custom [Design and Layout](https://docusaurus.io/docs/styling-layout) +- Add a [search bar](https://docusaurus.io/docs/search) +- Find inspirations in the [Docusaurus showcase](https://docusaurus.io/showcase) +- Get involved in the [Docusaurus Community](https://docusaurus.io/community/support) diff --git a/docs/docs/tutorial-basics/create-a-blog-post.md b/docs/docs/tutorial-basics/create-a-blog-post.md new file mode 100644 index 0000000000..550ae17ee1 --- /dev/null +++ b/docs/docs/tutorial-basics/create-a-blog-post.md @@ -0,0 +1,34 @@ +--- +sidebar_position: 3 +--- + +# Create a Blog Post + +Docusaurus creates a **page for each blog post**, but also a **blog index page**, a **tag system**, an **RSS** feed... + +## Create your first Post + +Create a file at `blog/2021-02-28-greetings.md`: + +```md title="blog/2021-02-28-greetings.md" +--- +slug: greetings +title: Greetings! +authors: + - name: Joel Marcey + title: Co-creator of Docusaurus 1 + url: https://github.com/JoelMarcey + image_url: https://github.com/JoelMarcey.png + - name: Sébastien Lorber + title: Docusaurus maintainer + url: https://sebastienlorber.com + image_url: https://github.com/slorber.png +tags: [greetings] +--- + +Congratulations, you have made your first post! + +Feel free to play around and edit this post as much as you like. +``` + +A new blog post is now available at [http://localhost:3000/blog/greetings](http://localhost:3000/blog/greetings). diff --git a/docs/docs/tutorial-basics/create-a-document.md b/docs/docs/tutorial-basics/create-a-document.md new file mode 100644 index 0000000000..c22fe29446 --- /dev/null +++ b/docs/docs/tutorial-basics/create-a-document.md @@ -0,0 +1,57 @@ +--- +sidebar_position: 2 +--- + +# Create a Document + +Documents are **groups of pages** connected through: + +- a **sidebar** +- **previous/next navigation** +- **versioning** + +## Create your first Doc + +Create a Markdown file at `docs/hello.md`: + +```md title="docs/hello.md" +# Hello + +This is my **first Docusaurus document**! +``` + +A new document is now available at [http://localhost:3000/docs/hello](http://localhost:3000/docs/hello). + +## Configure the Sidebar + +Docusaurus automatically **creates a sidebar** from the `docs` folder. + +Add metadata to customize the sidebar label and position: + +```md title="docs/hello.md" {1-4} +--- +sidebar_label: 'Hi!' +sidebar_position: 3 +--- + +# Hello + +This is my **first Docusaurus document**! +``` + +It is also possible to create your sidebar explicitly in `sidebars.js`: + +```js title="sidebars.js" +export default { + tutorialSidebar: [ + 'intro', + // highlight-next-line + 'hello', + { + type: 'category', + label: 'Tutorial', + items: ['tutorial-basics/create-a-document'], + }, + ], +}; +``` diff --git a/docs/docs/tutorial-basics/create-a-page.md b/docs/docs/tutorial-basics/create-a-page.md new file mode 100644 index 0000000000..20e2ac3005 --- /dev/null +++ b/docs/docs/tutorial-basics/create-a-page.md @@ -0,0 +1,43 @@ +--- +sidebar_position: 1 +--- + +# Create a Page + +Add **Markdown or React** files to `src/pages` to create a **standalone page**: + +- `src/pages/index.js` → `localhost:3000/` +- `src/pages/foo.md` → `localhost:3000/foo` +- `src/pages/foo/bar.js` → `localhost:3000/foo/bar` + +## Create your first React Page + +Create a file at `src/pages/my-react-page.js`: + +```jsx title="src/pages/my-react-page.js" +import React from 'react'; +import Layout from '@theme/Layout'; + +export default function MyReactPage() { + return ( + +

My React page

+

This is a React page

+
+ ); +} +``` + +A new page is now available at [http://localhost:3000/my-react-page](http://localhost:3000/my-react-page). + +## Create your first Markdown Page + +Create a file at `src/pages/my-markdown-page.md`: + +```mdx title="src/pages/my-markdown-page.md" +# My Markdown page + +This is a Markdown page +``` + +A new page is now available at [http://localhost:3000/my-markdown-page](http://localhost:3000/my-markdown-page). diff --git a/docs/docs/tutorial-basics/deploy-your-site.md b/docs/docs/tutorial-basics/deploy-your-site.md new file mode 100644 index 0000000000..1c50ee063e --- /dev/null +++ b/docs/docs/tutorial-basics/deploy-your-site.md @@ -0,0 +1,31 @@ +--- +sidebar_position: 5 +--- + +# Deploy your site + +Docusaurus is a **static-site-generator** (also called **[Jamstack](https://jamstack.org/)**). + +It builds your site as simple **static HTML, JavaScript and CSS files**. + +## Build your site + +Build your site **for production**: + +```bash +npm run build +``` + +The static files are generated in the `build` folder. + +## Deploy your site + +Test your production build locally: + +```bash +npm run serve +``` + +The `build` folder is now served at [http://localhost:3000/](http://localhost:3000/). + +You can now deploy the `build` folder **almost anywhere** easily, **for free** or very small cost (read the **[Deployment Guide](https://docusaurus.io/docs/deployment)**). diff --git a/docs/docs/tutorial-basics/markdown-features.mdx b/docs/docs/tutorial-basics/markdown-features.mdx new file mode 100644 index 0000000000..35e00825ed --- /dev/null +++ b/docs/docs/tutorial-basics/markdown-features.mdx @@ -0,0 +1,152 @@ +--- +sidebar_position: 4 +--- + +# Markdown Features + +Docusaurus supports **[Markdown](https://daringfireball.net/projects/markdown/syntax)** and a few **additional features**. + +## Front Matter + +Markdown documents have metadata at the top called [Front Matter](https://jekyllrb.com/docs/front-matter/): + +```text title="my-doc.md" +// highlight-start +--- +id: my-doc-id +title: My document title +description: My document description +slug: /my-custom-url +--- +// highlight-end + +## Markdown heading + +Markdown text with [links](./hello.md) +``` + +## Links + +Regular Markdown links are supported, using url paths or relative file paths. + +```md +Let's see how to [Create a page](/create-a-page). +``` + +```md +Let's see how to [Create a page](./create-a-page.md). +``` + +**Result:** Let's see how to [Create a page](./create-a-page.md). + +## Images + +Regular Markdown images are supported. + +You can use absolute paths to reference images in the static directory (`static/img/docusaurus.png`): + +```md +![Docusaurus logo](/img/docusaurus.png) +``` + +![Docusaurus logo](/img/docusaurus.png) + +You can reference images relative to the current file as well. This is particularly useful to colocate images close to the Markdown files using them: + +```md +![Docusaurus logo](./img/docusaurus.png) +``` + +## Code Blocks + +Markdown code blocks are supported with Syntax highlighting. + +````md +```jsx title="src/components/HelloDocusaurus.js" +function HelloDocusaurus() { + return

Hello, Docusaurus!

; +} +``` +```` + +```jsx title="src/components/HelloDocusaurus.js" +function HelloDocusaurus() { + return

Hello, Docusaurus!

; +} +``` + +## Admonitions + +Docusaurus has a special syntax to create admonitions and callouts: + +```md +:::tip My tip + +Use this awesome feature option + +::: + +:::danger Take care + +This action is dangerous + +::: +``` + +:::tip My tip + +Use this awesome feature option + +::: + +:::danger Take care + +This action is dangerous + +::: + +## MDX and React Components + +[MDX](https://mdxjs.com/) can make your documentation more **interactive** and allows using any **React components inside Markdown**: + +```jsx +export const Highlight = ({children, color}) => ( + { + alert(`You clicked the color ${color} with label ${children}`) + }}> + {children} + +); + +This is Docusaurus green ! + +This is Facebook blue ! +``` + +export const Highlight = ({children, color}) => ( + { + alert(`You clicked the color ${color} with label ${children}`); + }}> + {children} + +); + +This is Docusaurus green ! + +This is Facebook blue ! diff --git a/docs/docs/tutorial-extras/_category_.json b/docs/docs/tutorial-extras/_category_.json new file mode 100644 index 0000000000..a8ffcc1930 --- /dev/null +++ b/docs/docs/tutorial-extras/_category_.json @@ -0,0 +1,7 @@ +{ + "label": "Tutorial - Extras", + "position": 3, + "link": { + "type": "generated-index" + } +} diff --git a/docs/docs/tutorial-extras/img/docsVersionDropdown.png b/docs/docs/tutorial-extras/img/docsVersionDropdown.png new file mode 100644 index 0000000000..97e4164618 Binary files /dev/null and b/docs/docs/tutorial-extras/img/docsVersionDropdown.png differ diff --git a/docs/docs/tutorial-extras/img/localeDropdown.png b/docs/docs/tutorial-extras/img/localeDropdown.png new file mode 100644 index 0000000000..e257edc1f9 Binary files /dev/null and b/docs/docs/tutorial-extras/img/localeDropdown.png differ diff --git a/docs/docs/tutorial-extras/manage-docs-versions.md b/docs/docs/tutorial-extras/manage-docs-versions.md new file mode 100644 index 0000000000..ccda0b9076 --- /dev/null +++ b/docs/docs/tutorial-extras/manage-docs-versions.md @@ -0,0 +1,55 @@ +--- +sidebar_position: 1 +--- + +# Manage Docs Versions + +Docusaurus can manage multiple versions of your docs. + +## Create a docs version + +Release a version 1.0 of your project: + +```bash +npm run docusaurus docs:version 1.0 +``` + +The `docs` folder is copied into `versioned_docs/version-1.0` and `versions.json` is created. + +Your docs now have 2 versions: + +- `1.0` at `http://localhost:3000/docs/` for the version 1.0 docs +- `current` at `http://localhost:3000/docs/next/` for the **upcoming, unreleased docs** + +## Add a Version Dropdown + +To navigate seamlessly across versions, add a version dropdown. + +Modify the `docusaurus.config.js` file: + +```js title="docusaurus.config.js" +export default { + themeConfig: { + navbar: { + items: [ + // highlight-start + { + type: 'docsVersionDropdown', + }, + // highlight-end + ], + }, + }, +}; +``` + +The docs version dropdown appears in your navbar: + +![Docs Version Dropdown](./img/docsVersionDropdown.png) + +## Update an existing version + +It is possible to edit versioned docs in their respective folder: + +- `versioned_docs/version-1.0/hello.md` updates `http://localhost:3000/docs/hello` +- `docs/hello.md` updates `http://localhost:3000/docs/next/hello` diff --git a/docs/docs/tutorial-extras/translate-your-site.md b/docs/docs/tutorial-extras/translate-your-site.md new file mode 100644 index 0000000000..b5a644abdf --- /dev/null +++ b/docs/docs/tutorial-extras/translate-your-site.md @@ -0,0 +1,88 @@ +--- +sidebar_position: 2 +--- + +# Translate your site + +Let's translate `docs/intro.md` to French. + +## Configure i18n + +Modify `docusaurus.config.js` to add support for the `fr` locale: + +```js title="docusaurus.config.js" +export default { + i18n: { + defaultLocale: 'en', + locales: ['en', 'fr'], + }, +}; +``` + +## Translate a doc + +Copy the `docs/intro.md` file to the `i18n/fr` folder: + +```bash +mkdir -p i18n/fr/docusaurus-plugin-content-docs/current/ + +cp docs/intro.md i18n/fr/docusaurus-plugin-content-docs/current/intro.md +``` + +Translate `i18n/fr/docusaurus-plugin-content-docs/current/intro.md` in French. + +## Start your localized site + +Start your site on the French locale: + +```bash +npm run start -- --locale fr +``` + +Your localized site is accessible at [http://localhost:3000/fr/](http://localhost:3000/fr/) and the `Getting Started` page is translated. + +:::caution + +In development, you can only use one locale at a time. + +::: + +## Add a Locale Dropdown + +To navigate seamlessly across languages, add a locale dropdown. + +Modify the `docusaurus.config.js` file: + +```js title="docusaurus.config.js" +export default { + themeConfig: { + navbar: { + items: [ + // highlight-start + { + type: 'localeDropdown', + }, + // highlight-end + ], + }, + }, +}; +``` + +The locale dropdown now appears in your navbar: + +![Locale Dropdown](./img/localeDropdown.png) + +## Build your localized site + +Build your site for a specific locale: + +```bash +npm run build -- --locale fr +``` + +Or build your site to include all the locales at once: + +```bash +npm run build +``` diff --git a/docs/docusaurus.config.ts b/docs/docusaurus.config.ts new file mode 100644 index 0000000000..fe6e79534b --- /dev/null +++ b/docs/docusaurus.config.ts @@ -0,0 +1,119 @@ +import { themes as prismThemes } from 'prism-react-renderer'; +import type { Config } from '@docusaurus/types'; +import type * as Preset from '@docusaurus/preset-classic'; + +// This runs in Node.js - Don't use client-side code here (browser APIs, JSX...) + +const config: Config = { + title: 'Talawa-Admin Documentation', + tagline: 'Start your open source journey here', + favicon: 'img/favicon.ico', + + url: 'https://docs-admin.talawa.io', + baseUrl: '/', + deploymentBranch: 'gh-pages', + + organizationName: 'PalisadoesFoundation', // GitHub org + projectName: 'talawa-admin', // repo name + + onBrokenLinks: 'throw', + onBrokenMarkdownLinks: 'warn', + + // Even if you don't use internationalization, you can use this field to set + // useful metadata like html lang. For example, if your site is Chinese, you + // may want to replace "en" with "zh-Hans". + i18n: { + defaultLocale: 'en', + locales: ['en'], + }, + + presets: [ + [ + 'classic', + { + docs: { + sidebarPath: './sidebars.ts', + // Please change this to your repo. + // Remove this to remove the "edit this page" links. + editUrl: + 'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/', + }, + theme: { + customCss: './src/css/custom.css', + }, + } satisfies Preset.Options, + ], + ], + + themeConfig: { + // Replace with your project's social card + image: 'img/docusaurus-social-card.jpg', + navbar: { + title: 'My Site', + logo: { + alt: 'My Site Logo', + src: 'img/logo.svg', + }, + items: [ + { + type: 'docSidebar', + sidebarId: 'tutorialSidebar', + position: 'left', + label: 'Tutorial', + }, + { + href: 'https://github.com/facebook/docusaurus', + label: 'GitHub', + position: 'right', + }, + ], + }, + footer: { + style: 'dark', + links: [ + { + title: 'Docs', + items: [ + { + label: 'Tutorial', + to: '/docs/intro', + }, + ], + }, + { + title: 'Community', + items: [ + { + label: 'Stack Overflow', + href: 'https://stackoverflow.com/questions/tagged/docusaurus', + }, + { + label: 'Discord', + href: 'https://discordapp.com/invite/docusaurus', + }, + { + label: 'X', + href: 'https://x.com/docusaurus', + }, + ], + }, + { + title: 'More', + items: [ + { + label: 'GitHub', + href: 'https://github.com/facebook/docusaurus', + }, + ], + }, + ], + copyright: `Copyright © ${new Date().getFullYear()} My Project, Inc. Built with Docusaurus.`, + }, + prism: { + theme: prismThemes.github, + darkTheme: prismThemes.dracula, + }, + } satisfies Preset.ThemeConfig, +}; + +export default config; diff --git a/docs/package.json b/docs/package.json new file mode 100644 index 0000000000..65e9e455b5 --- /dev/null +++ b/docs/package.json @@ -0,0 +1,48 @@ +{ + "name": "docs", + "version": "0.0.0", + "private": true, + "scripts": { + "docusaurus": "docusaurus", + "start": "docusaurus start", + "build": "docusaurus build", + "swizzle": "docusaurus swizzle", + "deploy": "docusaurus deploy", + "clear": "docusaurus clear", + "serve": "docusaurus serve", + "write-translations": "docusaurus write-translations", + "write-heading-ids": "docusaurus write-heading-ids", + "typecheck": "tsc" + }, + "dependencies": { + "@docusaurus/core": "3.6.3", + "@docusaurus/preset-classic": "3.6.3", + "@mdx-js/react": "^3.0.0", + "clsx": "^2.0.0", + "docusaurus": "^1.14.7", + "prism-react-renderer": "^2.3.0", + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "devDependencies": { + "@docusaurus/module-type-aliases": "3.6.3", + "@docusaurus/tsconfig": "3.6.3", + "@docusaurus/types": "3.6.3", + "typescript": "~5.6.2" + }, + "browserslist": { + "production": [ + ">0.5%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 3 chrome version", + "last 3 firefox version", + "last 5 safari version" + ] + }, + "engines": { + "node": ">=18.0" + } +} diff --git a/docs/sidebars.ts b/docs/sidebars.ts new file mode 100644 index 0000000000..68d3ae97bc --- /dev/null +++ b/docs/sidebars.ts @@ -0,0 +1,33 @@ +import type { SidebarsConfig } from '@docusaurus/plugin-content-docs'; + +// This runs in Node.js - Don't use client-side code here (browser APIs, JSX...) + +/** + * Creating a sidebar enables you to: + - create an ordered group of docs + - render a sidebar for each doc of that group + - provide next/previous navigation + + The sidebars can be generated from the filesystem, or explicitly defined here. + + Create as many sidebars as you want. + */ +const sidebars: SidebarsConfig = { + // By default, Docusaurus generates a sidebar from the docs folder structure + tutorialSidebar: [{ type: 'autogenerated', dirName: '.' }], + + // But you can create a sidebar manually + /* + tutorialSidebar: [ + 'intro', + 'hello', + { + type: 'category', + label: 'Tutorial', + items: ['tutorial-basics/create-a-document'], + }, + ], + */ +}; + +export default sidebars; diff --git a/docs/src/components/HomepageFeatures/index.tsx b/docs/src/components/HomepageFeatures/index.tsx new file mode 100644 index 0000000000..7e72738d82 --- /dev/null +++ b/docs/src/components/HomepageFeatures/index.tsx @@ -0,0 +1,70 @@ +import clsx from 'clsx'; +import Heading from '@theme/Heading'; +import styles from './styles.module.css'; + +type FeatureItem = { + title: string; + Svg: React.ComponentType>; + description: JSX.Element; +}; + +const FeatureList: FeatureItem[] = [ + { + title: 'Easy to Use', + Svg: require('@site/static/img/undraw_docusaurus_mountain.svg').default, + description: ( + <> + Docusaurus was designed from the ground up to be easily installed and + used to get your website up and running quickly. + + ), + }, + { + title: 'Focus on What Matters', + Svg: require('@site/static/img/undraw_docusaurus_tree.svg').default, + description: ( + <> + Docusaurus lets you focus on your docs, and we'll do the chores. Go + ahead and move your docs into the docs directory. + + ), + }, + { + title: 'Powered by React', + Svg: require('@site/static/img/undraw_docusaurus_react.svg').default, + description: ( + <> + Extend or customize your website layout by reusing React. Docusaurus can + be extended while reusing the same header and footer. + + ), + }, +]; + +function Feature({ title, Svg, description }: FeatureItem) { + return ( +
+
+ +
+
+ {title} +

{description}

+
+
+ ); +} + +export default function HomepageFeatures(): JSX.Element { + return ( +
+
+
+ {FeatureList.map((props, idx) => ( + + ))} +
+
+
+ ); +} diff --git a/docs/src/components/HomepageFeatures/styles.module.css b/docs/src/components/HomepageFeatures/styles.module.css new file mode 100644 index 0000000000..b248eb2e5d --- /dev/null +++ b/docs/src/components/HomepageFeatures/styles.module.css @@ -0,0 +1,11 @@ +.features { + display: flex; + align-items: center; + padding: 2rem 0; + width: 100%; +} + +.featureSvg { + height: 200px; + width: 200px; +} diff --git a/docs/src/css/custom.css b/docs/src/css/custom.css new file mode 100644 index 0000000000..2bc6a4cfde --- /dev/null +++ b/docs/src/css/custom.css @@ -0,0 +1,30 @@ +/** + * Any CSS included here will be global. The classic template + * bundles Infima by default. Infima is a CSS framework designed to + * work well for content-centric websites. + */ + +/* You can override the default Infima variables here. */ +:root { + --ifm-color-primary: #2e8555; + --ifm-color-primary-dark: #29784c; + --ifm-color-primary-darker: #277148; + --ifm-color-primary-darkest: #205d3b; + --ifm-color-primary-light: #33925d; + --ifm-color-primary-lighter: #359962; + --ifm-color-primary-lightest: #3cad6e; + --ifm-code-font-size: 95%; + --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1); +} + +/* For readability concerns, you should choose a lighter palette in dark mode. */ +[data-theme='dark'] { + --ifm-color-primary: #25c2a0; + --ifm-color-primary-dark: #21af90; + --ifm-color-primary-darker: #1fa588; + --ifm-color-primary-darkest: #1a8870; + --ifm-color-primary-light: #29d5b0; + --ifm-color-primary-lighter: #32d8b4; + --ifm-color-primary-lightest: #4fddbf; + --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3); +} diff --git a/docs/src/pages/index.module.css b/docs/src/pages/index.module.css new file mode 100644 index 0000000000..9f71a5da77 --- /dev/null +++ b/docs/src/pages/index.module.css @@ -0,0 +1,23 @@ +/** + * CSS files with the .module.css suffix will be treated as CSS modules + * and scoped locally. + */ + +.heroBanner { + padding: 4rem 0; + text-align: center; + position: relative; + overflow: hidden; +} + +@media screen and (max-width: 996px) { + .heroBanner { + padding: 2rem; + } +} + +.buttons { + display: flex; + align-items: center; + justify-content: center; +} diff --git a/docs/src/pages/index.tsx b/docs/src/pages/index.tsx new file mode 100644 index 0000000000..270b7f9af8 --- /dev/null +++ b/docs/src/pages/index.tsx @@ -0,0 +1,45 @@ +import clsx from 'clsx'; +import Link from '@docusaurus/Link'; +import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; +import Layout from '@theme/Layout'; +import HomepageFeatures from '@site/src/components/HomepageFeatures'; +import Heading from '@theme/Heading'; + +import styles from './index.module.css'; + +function HomepageHeader() { + const { siteConfig } = useDocusaurusContext(); + return ( +
+
+ + {siteConfig.title} + +

{siteConfig.tagline}

+
+ + Docusaurus Tutorial - 5min ⏱️ + +
+
+
+ ); +} + +export default function Home(): JSX.Element { + const { siteConfig } = useDocusaurusContext(); + return ( + + +
+ +
+
+ ); +} diff --git a/docs/src/pages/markdown-page.md b/docs/src/pages/markdown-page.md new file mode 100644 index 0000000000..9756c5b668 --- /dev/null +++ b/docs/src/pages/markdown-page.md @@ -0,0 +1,7 @@ +--- +title: Markdown page example +--- + +# Markdown page example + +You don't need React to write simple standalone pages. diff --git a/docs/static/.nojekyll b/docs/static/.nojekyll new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/static/CNAME b/docs/static/CNAME new file mode 100644 index 0000000000..2594cfef31 --- /dev/null +++ b/docs/static/CNAME @@ -0,0 +1 @@ +docs-admin.talawa.io diff --git a/docs/static/img/docusaurus-social-card.jpg b/docs/static/img/docusaurus-social-card.jpg new file mode 100644 index 0000000000..ffcb448210 Binary files /dev/null and b/docs/static/img/docusaurus-social-card.jpg differ diff --git a/docs/static/img/docusaurus.png b/docs/static/img/docusaurus.png new file mode 100644 index 0000000000..f458149e3c Binary files /dev/null and b/docs/static/img/docusaurus.png differ diff --git a/docs/static/img/favicon.ico b/docs/static/img/favicon.ico new file mode 100644 index 0000000000..c01d54bcd3 Binary files /dev/null and b/docs/static/img/favicon.ico differ diff --git a/docs/static/img/logo.svg b/docs/static/img/logo.svg new file mode 100644 index 0000000000..9db6d0d066 --- /dev/null +++ b/docs/static/img/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/static/img/markdown/misc/logo.png b/docs/static/img/markdown/misc/logo.png new file mode 100644 index 0000000000..985fcfb1a3 Binary files /dev/null and b/docs/static/img/markdown/misc/logo.png differ diff --git a/docs/static/img/undraw_docusaurus_mountain.svg b/docs/static/img/undraw_docusaurus_mountain.svg new file mode 100644 index 0000000000..af961c49a8 --- /dev/null +++ b/docs/static/img/undraw_docusaurus_mountain.svg @@ -0,0 +1,171 @@ + + Easy to Use + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/static/img/undraw_docusaurus_react.svg b/docs/static/img/undraw_docusaurus_react.svg new file mode 100644 index 0000000000..94b5cf08f8 --- /dev/null +++ b/docs/static/img/undraw_docusaurus_react.svg @@ -0,0 +1,170 @@ + + Powered by React + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/static/img/undraw_docusaurus_tree.svg b/docs/static/img/undraw_docusaurus_tree.svg new file mode 100644 index 0000000000..d9161d3392 --- /dev/null +++ b/docs/static/img/undraw_docusaurus_tree.svg @@ -0,0 +1,40 @@ + + Focus on What Matters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dump.rdb b/dump.rdb new file mode 100644 index 0000000000..6d49ca7f96 Binary files /dev/null and b/dump.rdb differ diff --git a/jest.config.js b/jest.config.js index 4346984c74..75e0cc5b4d 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,16 +1,30 @@ export default { roots: ['/src'], - collectCoverageFrom: ['src/**/*.{ts,tsx}', '!src/index.tsx'], + collectCoverageFrom: [ + 'src/**/*.{ts,tsx}', + '!src/index.tsx', + '!node_modules', + '!dist', + '!**/*.{spec,test}.{js,jsx,ts,tsx}', + '!coverage/**', + '!**/index.{js,ts}', + '!**/*.d.ts', + '!src/test/**', + '!vitest.config.ts', + ], // setupFiles: ['react-app-polyfill/jsdom'], setupFiles: ['whatwg-fetch'], setupFilesAfterEnv: ['/src/setupTests.ts'], testMatch: [ '/src/**/__tests__/**/*.{js,jsx,ts,tsx}', - '/src/**/*.{spec,test}.{js,jsx,ts,tsx}', + '/src/**/*.test.{js,jsx,ts,tsx}', ], testEnvironment: 'jsdom', transform: { - '^.+\\.(js|jsx|ts|tsx)$': ['babel-jest', { configFile: "./config/babel.config.cjs" }], // Use babel-jest for JavaScript and TypeScript files + '^.+\\.(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 }, @@ -22,13 +36,15 @@ export default { '/src', ], moduleNameMapper: { + '\\.(css|scss|sass|less)$': 'identity-obj-proxy', '^react-native$': 'react-native-web', - '^@mui/(.*)$': '/node_modules/@mui/$1', '^@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', + '\\.svg$': '/scripts/__mocks__/fileMock.js', + '^@pdfme/generator$': '/scripts/__mocks__/@pdfme/generator.ts', + '\\.(css|less|scss|sass)$': 'identity-obj-proxy', }, moduleFileExtensions: [ 'web.js', @@ -65,4 +81,6 @@ export default { '/build/', '/public/', ], + coverageDirectory: './coverage/jest', + coverageReporters: ['text', 'html', 'text-summary', 'lcov'], }; diff --git a/package-lock.json b/package-lock.json index 8a44446d6e..9c801aa1c0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,25 +8,29 @@ "name": "talawa-admin", "version": "3.0.0", "dependencies": { - "@apollo/client": "^3.11.4", + "@apollo/client": "^3.11.8", "@apollo/link-error": "^2.0.0-beta.3", "@apollo/react-testing": "^4.0.0", - "@dicebear/collection": "^8.0.2", - "@dicebear/core": "^8.0.2", + "@dicebear/collection": "^9.2.2", + "@dicebear/core": "^9.2.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.17.0", - "@mui/x-data-grid": "^7.16.0", - "@mui/x-date-pickers": "^7.11.1", - "@pdfme/generator": "^4.5.2", + "@mui/base": "^5.0.0-beta.61", + "@mui/icons-material": "^6.1.6", + "@mui/material": "^6.1.6", + "@mui/private-theming": "^6.1.6", + "@mui/system": "^6.1.6", + "@mui/x-charts": "^7.22.2", + "@mui/x-data-grid": "^7.22.1", + "@mui/x-date-pickers": "^7.18.0", + "@pdfme/common": "^5.2.11", + "@pdfme/generator": "^5.2.3", + "@pdfme/schemas": "^5.1.6", "@reduxjs/toolkit": "^2.3.0", - "@vitejs/plugin-react": "^4.3.2", + "@vitejs/plugin-react": "^4.3.3", "babel-plugin-transform-import-meta": "^2.2.1", "bootstrap": "^5.3.3", + "chart.js": "^4.4.6", "customize-cra": "^1.0.0", "dayjs": "^1.11.13", "dotenv": "^16.4.5", @@ -38,13 +42,16 @@ "i18next": "^23.15.1", "i18next-browser-languagedetector": "^8.0.0", "i18next-http-backend": "^2.6.1", - "inquirer": "^8.0.0", + "inquirer": "^11.0.2", "js-cookie": "^3.0.1", + "lcov-result-merger": "^5.0.1", "markdown-toc": "^1.2.0", - "prettier": "^3.3.2", + "prettier": "^3.3.3", + "prop-types": "^15.8.1", "react": "^18.3.1", "react-beautiful-dnd": "^13.1.1", "react-bootstrap": "^2.10.5", + "react-chartjs-2": "^5.2.0", "react-datepicker": "^7.5.0", "react-dom": "^18.3.1", "react-google-recaptcha": "^3.1.0", @@ -59,41 +66,45 @@ "redux": "^5.0.1", "redux-thunk": "^3.1.0", "sanitize-html": "^2.13.0", - "typedoc": "^0.26.7", - "typedoc-plugin-markdown": "^4.2.1", + "typedoc": "^0.26.10", + "typedoc-plugin-markdown": "^4.2.10", "typescript": "^5.6.3", "vite": "^5.4.8", "vite-plugin-environment": "^1.1.3", - "vite-tsconfig-paths": "^5.0.1", - "web-vitals": "^4.2.3" + "vite-plugin-node-polyfills": "^0.22.0", + "vite-tsconfig-paths": "^5.1.3", + "web-vitals": "^4.2.4" }, "devDependencies": { "@babel/plugin-proposal-private-property-in-object": "^7.21.11", - "@babel/preset-env": "^7.25.4", + "@babel/preset-env": "^7.26.0", "@babel/preset-react": "^7.25.7", - "@babel/preset-typescript": "^7.24.7", - "@testing-library/jest-dom": "^6.5.0", + "@babel/preset-typescript": "^7.26.0", + "@testing-library/jest-dom": "^6.6.3", "@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": "^22.5.4", + "@types/node": "^22.9.0", "@types/node-fetch": "^2.6.10", - "@types/react": "^18.3.3", + "@types/react": "^18.3.12", "@types/react-beautiful-dnd": "^13.1.8", - "@types/react-bootstrap": "^0.32.32", + "@types/react-bootstrap": "^0.32.37", + "@types/react-chartjs-2": "^2.5.7", "@types/react-datepicker": "^7.0.0", - "@types/react-dom": "^18.3.0", + "@types/react-dom": "^18.3.1", "@types/react-google-recaptcha": "^2.1.9", "@types/react-router-dom": "^5.1.8", "@types/sanitize-html": "^2.13.0", - "@typescript-eslint/eslint-plugin": "^8.8.1", + "@typescript-eslint/eslint-plugin": "^8.11.0", "@typescript-eslint/parser": "^8.5.0", + "@vitest/coverage-istanbul": "^2.1.5", "babel-jest": "^29.7.0", "cross-env": "^7.0.3", + "eslint": "^8.49.0", "eslint-config-prettier": "^9.1.0", - "eslint-plugin-import": "^2.30.0", + "eslint-plugin-import": "^2.31.0", "eslint-plugin-jest": "^28.8.0", "eslint-plugin-prettier": "^5.2.1", "eslint-plugin-react": "^7.37.1", @@ -106,9 +117,10 @@ "jest-preview": "^0.3.1", "lint-staged": "^15.2.8", "postcss-modules": "^6.0.0", - "sass": "^1.77.8", + "sass": "^1.80.7", "tsx": "^4.19.1", "vite-plugin-svgr": "^4.2.0", + "vitest": "^2.1.5", "whatwg-fetch": "^3.6.20" }, "engines": { @@ -120,7 +132,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" } @@ -144,10 +155,145 @@ "node": ">=6.0.0" } }, + "node_modules/@ant-design/colors": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-7.1.0.tgz", + "integrity": "sha512-MMoDGWn1y9LdQJQSHiCC20x3uZ3CwQnv9QMz6pCmJOrqdgM9YxsoVVY0wtrdXbmfSgnV0KNk6zi09NAhMR2jvg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@ctrl/tinycolor": "^3.6.1" + } + }, + "node_modules/@ant-design/cssinjs": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/@ant-design/cssinjs/-/cssinjs-1.22.1.tgz", + "integrity": "sha512-SLuXM4wiEE1blOx94iXrkOgseMZHzdr4ngdFu3VVDq6AOWh7rlwqTkMAtJho3EsBF6x/eUGOtK53VZXGQG7+sQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.11.1", + "@emotion/hash": "^0.8.0", + "@emotion/unitless": "^0.7.5", + "classnames": "^2.3.1", + "csstype": "^3.1.3", + "rc-util": "^5.35.0", + "stylis": "^4.3.4" + }, + "peerDependencies": { + "react": ">=16.0.0", + "react-dom": ">=16.0.0" + } + }, + "node_modules/@ant-design/cssinjs-utils": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@ant-design/cssinjs-utils/-/cssinjs-utils-1.1.3.tgz", + "integrity": "sha512-nOoQMLW1l+xR1Co8NFVYiP8pZp3VjIIzqV6D6ShYF2ljtdwWJn5WSsH+7kvCktXL/yhEtWURKOfH5Xz/gzlwsg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@ant-design/cssinjs": "^1.21.0", + "@babel/runtime": "^7.23.2", + "rc-util": "^5.38.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@ant-design/cssinjs/node_modules/@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==", + "license": "MIT", + "peer": true + }, + "node_modules/@ant-design/cssinjs/node_modules/@emotion/unitless": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", + "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==", + "license": "MIT", + "peer": true + }, + "node_modules/@ant-design/cssinjs/node_modules/stylis": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.4.tgz", + "integrity": "sha512-osIBl6BGUmSfDkyH2mB7EFvCJntXDrLhKjHTRj/rK6xLH0yuPrHULDRQzKokSOD4VoorhtKpfcfW1GAntu8now==", + "license": "MIT", + "peer": true + }, + "node_modules/@ant-design/fast-color": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@ant-design/fast-color/-/fast-color-2.0.6.tgz", + "integrity": "sha512-y2217gk4NqL35giHl72o6Zzqji9O7vHh9YmhUVkPtAOpoTCH4uWxo/pr4VE8t0+ChEPs0qo4eJRC5Q1eXWo3vA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.24.7" + }, + "engines": { + "node": ">=8.x" + } + }, + "node_modules/@ant-design/icons": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-5.5.2.tgz", + "integrity": "sha512-xc53rjVBl9v2BqFxUjZGti/RfdDeA8/6KYglmInM2PNqSXc/WfuGDTifJI/ZsokJK0aeKvOIbXc9y2g8ILAhEA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@ant-design/colors": "^7.0.0", + "@ant-design/icons-svg": "^4.4.0", + "@babel/runtime": "^7.24.8", + "classnames": "^2.2.6", + "rc-util": "^5.31.1" + }, + "engines": { + "node": ">=8" + }, + "peerDependencies": { + "react": ">=16.0.0", + "react-dom": ">=16.0.0" + } + }, + "node_modules/@ant-design/icons-svg": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.4.2.tgz", + "integrity": "sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA==", + "license": "MIT", + "peer": true + }, + "node_modules/@ant-design/react-slick": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ant-design/react-slick/-/react-slick-1.1.2.tgz", + "integrity": "sha512-EzlvzE6xQUBrZuuhSAFTdsr4P2bBBHGZwKFemEfq8gIGyIQCxalYfZW/T2ORbtQx5rU69o+WycP3exY/7T1hGA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.10.4", + "classnames": "^2.2.5", + "json2mq": "^0.2.0", + "resize-observer-polyfill": "^1.5.1", + "throttle-debounce": "^5.0.0" + }, + "peerDependencies": { + "react": ">=16.9.0" + } + }, + "node_modules/@ant-design/react-slick/node_modules/throttle-debounce": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-5.0.2.tgz", + "integrity": "sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12.22" + } + }, "node_modules/@apollo/client": { - "version": "3.11.4", - "resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.11.4.tgz", - "integrity": "sha512-bmgYKkULpym8wt8aXlAZ1heaYo0skLJ5ru0qJ+JCRoo03Pe+yIDbBCnqlDw6Mjj76hFkDw3HwFMgZC2Hxp30Mg==", + "version": "3.11.8", + "resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.11.8.tgz", + "integrity": "sha512-CgG1wbtMjsV2pRGe/eYITmV5B8lXUCYljB2gB/6jWTFQcrvirUVvKg7qtFdjYkQSFbIffU1IDyxgeaN81eTjbA==", "dependencies": { "@graphql-typed-document-node/core": "^3.1.1", "@wry/caches": "^1.0.0", @@ -209,12 +355,12 @@ } }, "node_modules/@babel/code-frame": { - "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", + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", "dependencies": { - "@babel/highlight": "^7.25.7", + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", "picocolors": "^1.0.0" }, "engines": { @@ -222,9 +368,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.4.tgz", - "integrity": "sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==", + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.2.tgz", + "integrity": "sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==", "engines": { "node": ">=6.9.0" } @@ -272,12 +418,12 @@ } }, "node_modules/@babel/generator": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.7.tgz", - "integrity": "sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA==", - "license": "MIT", + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.2.tgz", + "integrity": "sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==", "dependencies": { - "@babel/types": "^7.25.7", + "@babel/parser": "^7.26.2", + "@babel/types": "^7.26.0", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" @@ -287,39 +433,38 @@ } }, "node_modules/@babel/helper-annotate-as-pure": { - "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==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", + "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/types": "^7.25.7" + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.7.tgz", - "integrity": "sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.25.9.tgz", + "integrity": "sha512-C47lC7LIDCnz0h4vai/tpNOI95tCd5ZT3iBt/DBH5lXKHZsyNQv18yf1wIIg2ntiQNgmAvA+DgZ82iW8Qdym8g==", "dev": true, "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz", - "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz", + "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==", "dependencies": { - "@babel/compat-data": "^7.25.2", - "@babel/helper-validator-option": "^7.24.8", - "browserslist": "^4.23.1", + "@babel/compat-data": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -336,17 +481,17 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "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==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.9.tgz", + "integrity": "sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==", "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", + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/traverse": "^7.25.9", "semver": "^6.3.1" }, "engines": { @@ -366,13 +511,13 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "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==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.9.tgz", + "integrity": "sha512-ORPNZ3h6ZRkOyAa/SaHU+XsLZr0UQzRwuDQ0cczIA17nAzZ+85G5cVkOJIj7QavLZGSe8QXUmNFxSZzjcZF9bw==", "dev": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "regexpu-core": "^5.3.1", + "@babel/helper-annotate-as-pure": "^7.25.9", + "regexpu-core": "^6.1.1", "semver": "^6.3.1" }, "engines": { @@ -408,40 +553,38 @@ } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz", - "integrity": "sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", + "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==", "dev": true, "dependencies": { - "@babel/traverse": "^7.24.8", - "@babel/types": "^7.24.8" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "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", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", + "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", "dependencies": { - "@babel/traverse": "^7.25.7", - "@babel/types": "^7.25.7" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "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==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", + "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", "dependencies": { - "@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" + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -451,35 +594,34 @@ } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz", - "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz", + "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==", "dev": true, "dependencies": { - "@babel/types": "^7.24.7" + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "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", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", + "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-remap-async-to-generator": { - "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==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.9.tgz", + "integrity": "sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw==", "dev": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-wrap-function": "^7.25.0", - "@babel/traverse": "^7.25.0" + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-wrap-function": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -489,14 +631,14 @@ } }, "node_modules/@babel/helper-replace-supers": { - "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==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.9.tgz", + "integrity": "sha512-IiDqTOTBQy0sWyeXyGSC5TBJpGFXBkRynjBeXsvbhQFKj2viwJC76Epz35YLU1fpe/Am6Vppb7W7zM4fPQzLsQ==", "dev": true, "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.24.8", - "@babel/helper-optimise-call-expression": "^7.24.7", - "@babel/traverse": "^7.25.0" + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -506,66 +648,64 @@ } }, "node_modules/@babel/helper-simple-access": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", - "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.25.9.tgz", + "integrity": "sha512-c6WHXuiaRsJTyHYLJV75t9IqsmTbItYfdj99PnzYGQZkYKvan5/2jKJ7gu31J3/BJ/A18grImSPModuyG/Eo0Q==", + "dev": true, "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz", - "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", + "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==", "dev": true, "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "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", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "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", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "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", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", + "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-wrap-function": { - "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==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.9.tgz", + "integrity": "sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==", "dev": true, "dependencies": { - "@babel/template": "^7.25.0", - "@babel/traverse": "^7.25.0", - "@babel/types": "^7.25.0" + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -583,99 +723,12 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/highlight": { - "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.25.7", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "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" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/parser": { - "version": "7.25.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.8.tgz", - "integrity": "sha512-HcttkxzdPucv3nNFmfOOMfFf64KgdJVqm1KaCm25dPGMLElo9nsLvXeJECQg8UzPuBGLyTSA0ZzqCtDSzKTEoQ==", - "license": "MIT", + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.2.tgz", + "integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==", "dependencies": { - "@babel/types": "^7.25.8" + "@babel/types": "^7.26.0" }, "bin": { "parser": "bin/babel-parser.js" @@ -685,13 +738,13 @@ } }, "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==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.9.tgz", + "integrity": "sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/traverse": "^7.25.3" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -701,12 +754,12 @@ } }, "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==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.9.tgz", + "integrity": "sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -716,12 +769,12 @@ } }, "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==", + "version": "7.25.9", + "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.9.tgz", + "integrity": "sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -731,14 +784,14 @@ } }, "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==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.9.tgz", + "integrity": "sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", - "@babel/plugin-transform-optional-chaining": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/plugin-transform-optional-chaining": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -748,13 +801,13 @@ } }, "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==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.9.tgz", + "integrity": "sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/traverse": "^7.25.0" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -817,52 +870,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-import-assertions": { - "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==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.26.0.tgz", + "integrity": "sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -872,12 +886,12 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "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==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", + "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -911,13 +925,12 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "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==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", + "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1029,12 +1042,12 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "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==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz", + "integrity": "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1060,12 +1073,12 @@ } }, "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.7.tgz", - "integrity": "sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.9.tgz", + "integrity": "sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1075,15 +1088,14 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "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==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.9.tgz", + "integrity": "sha512-RXV6QAzTBbhDMO9fWwOmwwTuYaiPbggWQ9INdZqAYeSHyG7FzQ+nOZaUUjNwKv9pV3aE4WFqFm1Hnbci5tBCAw==", "dev": true, "dependencies": { - "@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" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-remap-async-to-generator": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1093,14 +1105,14 @@ } }, "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.7.tgz", - "integrity": "sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.9.tgz", + "integrity": "sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ==", "dev": true, "dependencies": { - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-remap-async-to-generator": "^7.24.7" + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-remap-async-to-generator": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1110,12 +1122,12 @@ } }, "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.7.tgz", - "integrity": "sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.25.9.tgz", + "integrity": "sha512-toHc9fzab0ZfenFpsyYinOX0J/5dgJVA2fm64xPewu7CoYHWEivIWKxkK2rMi4r3yQqLnVmheMXRdG+k239CgA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1125,12 +1137,12 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "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==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.9.tgz", + "integrity": "sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1140,13 +1152,13 @@ } }, "node_modules/@babel/plugin-transform-class-properties": { - "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==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.9.tgz", + "integrity": "sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q==", "dev": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.25.4", - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1156,14 +1168,13 @@ } }, "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.7.tgz", - "integrity": "sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.26.0.tgz", + "integrity": "sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ==", "dev": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-class-static-block": "^7.14.5" + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1173,16 +1184,16 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "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==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.9.tgz", + "integrity": "sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==", "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", + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9", + "@babel/traverse": "^7.25.9", "globals": "^11.1.0" }, "engines": { @@ -1193,13 +1204,13 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz", - "integrity": "sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.9.tgz", + "integrity": "sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/template": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/template": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1209,12 +1220,12 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.8.tgz", - "integrity": "sha512-36e87mfY8TnRxc7yc6M9g9gOB7rKgSahqkIKwLpz4Ppk2+zC2Cy1is0uwtuSG6AE4zlTOUa+7JGz9jCJGLqQFQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.9.tgz", + "integrity": "sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1224,13 +1235,13 @@ } }, "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.7.tgz", - "integrity": "sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.9.tgz", + "integrity": "sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1240,12 +1251,12 @@ } }, "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.7.tgz", - "integrity": "sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.9.tgz", + "integrity": "sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1255,13 +1266,13 @@ } }, "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==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.9.tgz", + "integrity": "sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.0", - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1271,13 +1282,12 @@ } }, "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==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.9.tgz", + "integrity": "sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1287,13 +1297,13 @@ } }, "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==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.25.9.tgz", + "integrity": "sha512-KRhdhlVk2nObA5AYa7QMgTMTVJdfHprfpAk4DjZVtllqRg9qarilstTKEhpVjyt+Npi8ThRyiV8176Am3CodPA==", "dev": true, "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1303,13 +1313,12 @@ } }, "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==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.9.tgz", + "integrity": "sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1319,13 +1328,13 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.7.tgz", - "integrity": "sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.9.tgz", + "integrity": "sha512-LqHxduHoaGELJl2uhImHwRQudhCM50pT46rIBNvtT/Oql3nqiS3wOwP+5ten7NpYSXrrVLgtZU3DZmPtWZo16A==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1335,14 +1344,14 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "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==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.9.tgz", + "integrity": "sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==", "dev": true, "dependencies": { - "@babel/helper-compilation-targets": "^7.24.8", - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/traverse": "^7.25.1" + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1352,13 +1361,12 @@ } }, "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.7.tgz", - "integrity": "sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.9.tgz", + "integrity": "sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-json-strings": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1368,12 +1376,12 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "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==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.9.tgz", + "integrity": "sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1383,13 +1391,12 @@ } }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.7.tgz", - "integrity": "sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.9.tgz", + "integrity": "sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1399,12 +1406,12 @@ } }, "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.7.tgz", - "integrity": "sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.9.tgz", + "integrity": "sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1414,13 +1421,13 @@ } }, "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.7.tgz", - "integrity": "sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.9.tgz", + "integrity": "sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1430,14 +1437,14 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.8.tgz", - "integrity": "sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.25.9.tgz", + "integrity": "sha512-dwh2Ol1jWwL2MgkCzUSOvfmKElqQcuswAZypBSUsScMXvgdT8Ekq5YA6TtqpTVWH+4903NmboMuH1o9i8Rxlyg==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.24.8", - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/helper-simple-access": "^7.24.7" + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-simple-access": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1447,15 +1454,15 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "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==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.9.tgz", + "integrity": "sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA==", "dev": true, "dependencies": { - "@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" + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1465,13 +1472,13 @@ } }, "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.7.tgz", - "integrity": "sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.9.tgz", + "integrity": "sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1481,13 +1488,13 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.7.tgz", - "integrity": "sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.9.tgz", + "integrity": "sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1497,12 +1504,12 @@ } }, "node_modules/@babel/plugin-transform-new-target": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.7.tgz", - "integrity": "sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.9.tgz", + "integrity": "sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1512,13 +1519,12 @@ } }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.7.tgz", - "integrity": "sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.25.9.tgz", + "integrity": "sha512-ENfftpLZw5EItALAD4WsY/KUWvhUlZndm5GC7G3evUsVeSJB6p0pBeLQUnRnBCBx7zV0RKQjR9kCuwrsIrjWog==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1528,13 +1534,12 @@ } }, "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.7.tgz", - "integrity": "sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.9.tgz", + "integrity": "sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1544,15 +1549,14 @@ } }, "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.7.tgz", - "integrity": "sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.9.tgz", + "integrity": "sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg==", "dev": true, "dependencies": { - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.24.7" + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/plugin-transform-parameters": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1562,13 +1566,13 @@ } }, "node_modules/@babel/plugin-transform-object-super": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.7.tgz", - "integrity": "sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.9.tgz", + "integrity": "sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-replace-supers": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1578,13 +1582,12 @@ } }, "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.7.tgz", - "integrity": "sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.9.tgz", + "integrity": "sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1594,14 +1597,13 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.8.tgz", - "integrity": "sha512-5cTOLSMs9eypEy8JUVvIKOu6NgvbJMnpG62VpIHrTmROdQ+L5mDAaI40g25k5vXti55JWNX5jCkq3HZxXBQANw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.9.tgz", + "integrity": "sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1611,12 +1613,12 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.7.tgz", - "integrity": "sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.9.tgz", + "integrity": "sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1626,13 +1628,13 @@ } }, "node_modules/@babel/plugin-transform-private-methods": { - "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==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.9.tgz", + "integrity": "sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw==", "dev": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.25.4", - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1642,15 +1644,14 @@ } }, "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.7.tgz", - "integrity": "sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.9.tgz", + "integrity": "sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw==", "dev": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1660,12 +1661,12 @@ } }, "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.7.tgz", - "integrity": "sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.9.tgz", + "integrity": "sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1772,12 +1773,12 @@ } }, "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==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.9.tgz", + "integrity": "sha512-vwDcDNsgMPDGP0nMqzahDWE5/MLcX8sv96+wfX7as7LoF/kr97Bo/7fI00lXY4wUXYfVmwIIyG80fGZ1uvt2qg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-plugin-utils": "^7.25.9", "regenerator-transform": "^0.15.2" }, "engines": { @@ -1787,13 +1788,29 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.26.0.tgz", + "integrity": "sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.7.tgz", - "integrity": "sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.9.tgz", + "integrity": "sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1803,12 +1820,12 @@ } }, "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.7.tgz", - "integrity": "sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.9.tgz", + "integrity": "sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1818,13 +1835,13 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.7.tgz", - "integrity": "sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.9.tgz", + "integrity": "sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1834,12 +1851,12 @@ } }, "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.7.tgz", - "integrity": "sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.9.tgz", + "integrity": "sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1849,12 +1866,12 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.7.tgz", - "integrity": "sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.9.tgz", + "integrity": "sha512-o97AE4syN71M/lxrCtQByzphAdlYluKPDBzDVzMmfCobUjjhAryZV0AIpRPrxN0eAkxXO6ZLEScmt+PNhj2OTw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1864,12 +1881,12 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.8.tgz", - "integrity": "sha512-adNTUpDCVnmAE58VEqKlAA6ZBlNkMnWD0ZcW76lyNFN3MJniyGFZfNwERVk8Ap56MCnXztmDr19T4mPTztcuaw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.25.9.tgz", + "integrity": "sha512-v61XqUMiueJROUv66BVIOi0Fv/CUuZuZMl5NkRoCVxLAnMexZ0A3kMe7vvZ0nulxMuMp0Mk6S5hNh48yki08ZA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1879,16 +1896,16 @@ } }, "node_modules/@babel/plugin-transform-typescript": { - "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==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.25.9.tgz", + "integrity": "sha512-7PbZQZP50tzv2KGGnhh82GSyMB01yKY9scIjf1a+GfZCtInOWqUH5+1EBU4t9fyR5Oykkkc9vFTs4OHrhHXljQ==", "dev": true, "dependencies": { - "@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" + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/plugin-syntax-typescript": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1898,12 +1915,12 @@ } }, "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.7.tgz", - "integrity": "sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.9.tgz", + "integrity": "sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1913,13 +1930,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.7.tgz", - "integrity": "sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.9.tgz", + "integrity": "sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1929,13 +1946,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.7.tgz", - "integrity": "sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.9.tgz", + "integrity": "sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1945,13 +1962,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "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==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.9.tgz", + "integrity": "sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.2", - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1961,93 +1978,79 @@ } }, "node_modules/@babel/preset-env": { - "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.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", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.0.tgz", + "integrity": "sha512-H84Fxq0CQJNdPFT2DrfnylZ3cf5K43rGfWK4LJGPpjKHiZlk0/RzwEus3PDDZZg+/Er7lCA03MVacueUuXdzfw==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.26.0", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.9", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.9", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.9", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.25.9", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.9", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-import-assertions": "^7.24.7", - "@babel/plugin-syntax-import-attributes": "^7.24.7", - "@babel/plugin-syntax-import-meta": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-import-assertions": "^7.26.0", + "@babel/plugin-syntax-import-attributes": "^7.26.0", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@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/plugin-transform-arrow-functions": "^7.25.9", + "@babel/plugin-transform-async-generator-functions": "^7.25.9", + "@babel/plugin-transform-async-to-generator": "^7.25.9", + "@babel/plugin-transform-block-scoped-functions": "^7.25.9", + "@babel/plugin-transform-block-scoping": "^7.25.9", + "@babel/plugin-transform-class-properties": "^7.25.9", + "@babel/plugin-transform-class-static-block": "^7.26.0", + "@babel/plugin-transform-classes": "^7.25.9", + "@babel/plugin-transform-computed-properties": "^7.25.9", + "@babel/plugin-transform-destructuring": "^7.25.9", + "@babel/plugin-transform-dotall-regex": "^7.25.9", + "@babel/plugin-transform-duplicate-keys": "^7.25.9", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.9", + "@babel/plugin-transform-dynamic-import": "^7.25.9", + "@babel/plugin-transform-exponentiation-operator": "^7.25.9", + "@babel/plugin-transform-export-namespace-from": "^7.25.9", + "@babel/plugin-transform-for-of": "^7.25.9", + "@babel/plugin-transform-function-name": "^7.25.9", + "@babel/plugin-transform-json-strings": "^7.25.9", + "@babel/plugin-transform-literals": "^7.25.9", + "@babel/plugin-transform-logical-assignment-operators": "^7.25.9", + "@babel/plugin-transform-member-expression-literals": "^7.25.9", + "@babel/plugin-transform-modules-amd": "^7.25.9", + "@babel/plugin-transform-modules-commonjs": "^7.25.9", + "@babel/plugin-transform-modules-systemjs": "^7.25.9", + "@babel/plugin-transform-modules-umd": "^7.25.9", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.9", + "@babel/plugin-transform-new-target": "^7.25.9", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.25.9", + "@babel/plugin-transform-numeric-separator": "^7.25.9", + "@babel/plugin-transform-object-rest-spread": "^7.25.9", + "@babel/plugin-transform-object-super": "^7.25.9", + "@babel/plugin-transform-optional-catch-binding": "^7.25.9", + "@babel/plugin-transform-optional-chaining": "^7.25.9", + "@babel/plugin-transform-parameters": "^7.25.9", + "@babel/plugin-transform-private-methods": "^7.25.9", + "@babel/plugin-transform-private-property-in-object": "^7.25.9", + "@babel/plugin-transform-property-literals": "^7.25.9", + "@babel/plugin-transform-regenerator": "^7.25.9", + "@babel/plugin-transform-regexp-modifiers": "^7.26.0", + "@babel/plugin-transform-reserved-words": "^7.25.9", + "@babel/plugin-transform-shorthand-properties": "^7.25.9", + "@babel/plugin-transform-spread": "^7.25.9", + "@babel/plugin-transform-sticky-regex": "^7.25.9", + "@babel/plugin-transform-template-literals": "^7.25.9", + "@babel/plugin-transform-typeof-symbol": "^7.25.9", + "@babel/plugin-transform-unicode-escapes": "^7.25.9", + "@babel/plugin-transform-unicode-property-regex": "^7.25.9", + "@babel/plugin-transform-unicode-regex": "^7.25.9", + "@babel/plugin-transform-unicode-sets-regex": "^7.25.9", "@babel/preset-modules": "0.1.6-no-external-plugins", "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", + "core-js-compat": "^3.38.1", "semver": "^6.3.1" }, "engines": { @@ -2114,16 +2117,16 @@ } }, "node_modules/@babel/preset-typescript": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.24.7.tgz", - "integrity": "sha512-SyXRe3OdWwIwalxDg5UtJnJQO+YPcTfwiIY2B0Xlddh9o7jpWLvv8X1RthIeDOxQ+O1ML5BLPCONToObyVQVuQ==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.26.0.tgz", + "integrity": "sha512-NMk1IGZ5I/oHhoXEElcm+xUnL/szL6xflkFZmoEU9xj1qSJXpiS7rsspYo92B4DRCDvZn2erT5LdsCeXAKNCkg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-validator-option": "^7.24.7", - "@babel/plugin-syntax-jsx": "^7.24.7", - "@babel/plugin-transform-modules-commonjs": "^7.24.7", - "@babel/plugin-transform-typescript": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "@babel/plugin-syntax-jsx": "^7.25.9", + "@babel/plugin-transform-modules-commonjs": "^7.25.9", + "@babel/plugin-transform-typescript": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2132,16 +2135,10 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/regjsgen": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", - "dev": true - }, "node_modules/@babel/runtime": { - "version": "7.25.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.6.tgz", - "integrity": "sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==", + "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" }, @@ -2155,30 +2152,28 @@ "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" }, "node_modules/@babel/template": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.7.tgz", - "integrity": "sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA==", - "license": "MIT", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", + "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", "dependencies": { - "@babel/code-frame": "^7.25.7", - "@babel/parser": "^7.25.7", - "@babel/types": "^7.25.7" + "@babel/code-frame": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "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", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz", + "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==", + "dependencies": { + "@babel/code-frame": "^7.25.9", + "@babel/generator": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/template": "^7.25.9", + "@babel/types": "^7.25.9", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -2187,14 +2182,12 @@ } }, "node_modules/@babel/types": { - "version": "7.25.8", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.8.tgz", - "integrity": "sha512-JWtuCu8VQsMladxVz/P4HzHUGCAwpuqacmowgXFs5XjxIgKuNjnLokQzuVjlTvIzODaDmpjT3oxcC48vyk9EWg==", - "license": "MIT", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz", + "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", "dependencies": { - "@babel/helper-string-parser": "^7.25.7", - "@babel/helper-validator-identifier": "^7.25.7", - "to-fast-properties": "^2.0.0" + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2206,422 +2199,398 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, - "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==", + "node_modules/@ctrl/tinycolor": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", + "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==", "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@dicebear/adventurer": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@dicebear/adventurer/-/adventurer-9.2.2.tgz", + "integrity": "sha512-WjBXCP9EXbUul2zC3BS2/R3/4diw1uh/lU4jTEnujK1mhqwIwanFboIMzQsasNNL/xf+m3OHN7MUNJfHZ1fLZA==", "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { - "@dicebear/core": "^8.0.0" + "@dicebear/core": "^9.0.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", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@dicebear/adventurer-neutral/-/adventurer-neutral-9.2.2.tgz", + "integrity": "sha512-XVAjhUWjav6luTZ7txz8zVJU/H0DiUy4uU1Z7IO5MDO6kWvum+If1+0OUgEWYZwM+RDI7rt2CgVP910DyZGd1w==", "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { - "@dicebear/core": "^8.0.0" + "@dicebear/core": "^9.0.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", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@dicebear/avataaars/-/avataaars-9.2.2.tgz", + "integrity": "sha512-WqJPQEt0OhBybTpI0TqU1uD1pSk9M2+VPIwvBye/dXo46b+0jHGpftmxjQwk6tX8z0+mRko8pwV5n+cWht1/+w==", "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { - "@dicebear/core": "^8.0.0" + "@dicebear/core": "^9.0.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", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@dicebear/avataaars-neutral/-/avataaars-neutral-9.2.2.tgz", + "integrity": "sha512-pRj16P27dFDBI3LtdiHUDwIXIGndHAbZf5AxaMkn6/+0X93mVQ/btVJDXyW0G96WCsyC88wKAWr6/KJotPxU6Q==", "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { - "@dicebear/core": "^8.0.0" + "@dicebear/core": "^9.0.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", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@dicebear/big-ears/-/big-ears-9.2.2.tgz", + "integrity": "sha512-hz4UXdPq4qqZpu0YVvlqM4RDFhk5i0WgPcuwj/MOLlgTjuj63uHUhCQSk6ZiW1DQOs12qpwUBMGWVHxBRBas9g==", "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { - "@dicebear/core": "^8.0.0" + "@dicebear/core": "^9.0.0" } }, "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", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@dicebear/big-ears-neutral/-/big-ears-neutral-9.2.2.tgz", + "integrity": "sha512-IPHt8fi3dv9cyfBJBZ4s8T+PhFCrQvOCf91iRHBT3iOLNPdyZpI5GNLmGiV0XMAvIDP5NvA5+f6wdoBLhYhbDA==", "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { - "@dicebear/core": "^8.0.0" + "@dicebear/core": "^9.0.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", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@dicebear/big-smile/-/big-smile-9.2.2.tgz", + "integrity": "sha512-D4td0GL8or1nTNnXvZqkEXlzyqzGPWs3znOnm1HIohtFTeIwXm72Ob2lNDsaQJSJvXmVlwaQQ0CCTvyCl8Stjw==", "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { - "@dicebear/core": "^8.0.0" + "@dicebear/core": "^9.0.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", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@dicebear/bottts/-/bottts-9.2.2.tgz", + "integrity": "sha512-wugFkzw8JNWV1nftq/Wp/vmQsLAXDxrMtRK3AoMODuUpSVoP3EHRUfKS043xggOsQFvoj0HZ7kadmhn0AMLf5A==", "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { - "@dicebear/core": "^8.0.0" + "@dicebear/core": "^9.0.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", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@dicebear/bottts-neutral/-/bottts-neutral-9.2.2.tgz", + "integrity": "sha512-lSgpqmSJtlnyxVuUgNdBwyzuA0O9xa5zRJtz7x2KyWbicXir5iYdX0MVMCkp1EDvlcxm9rGJsclktugOyakTlw==", "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { - "@dicebear/core": "^8.0.0" + "@dicebear/core": "^9.0.0" } }, "node_modules/@dicebear/collection": { - "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" - }, - "peerDependencies": { - "@dicebear/core": "^8.0.0" - } - }, - "node_modules/@dicebear/converter": { - "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" + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@dicebear/collection/-/collection-9.2.2.tgz", + "integrity": "sha512-vZAmXhPWCK3sf8Fj9/QflFC6XOLroJOT5K1HdnzHaPboEvffUQideGCrrEamnJtlH0iF0ZDXh8gqmwy2fu+yHA==", + "dependencies": { + "@dicebear/adventurer": "9.2.2", + "@dicebear/adventurer-neutral": "9.2.2", + "@dicebear/avataaars": "9.2.2", + "@dicebear/avataaars-neutral": "9.2.2", + "@dicebear/big-ears": "9.2.2", + "@dicebear/big-ears-neutral": "9.2.2", + "@dicebear/big-smile": "9.2.2", + "@dicebear/bottts": "9.2.2", + "@dicebear/bottts-neutral": "9.2.2", + "@dicebear/croodles": "9.2.2", + "@dicebear/croodles-neutral": "9.2.2", + "@dicebear/dylan": "9.2.2", + "@dicebear/fun-emoji": "9.2.2", + "@dicebear/glass": "9.2.2", + "@dicebear/icons": "9.2.2", + "@dicebear/identicon": "9.2.2", + "@dicebear/initials": "9.2.2", + "@dicebear/lorelei": "9.2.2", + "@dicebear/lorelei-neutral": "9.2.2", + "@dicebear/micah": "9.2.2", + "@dicebear/miniavs": "9.2.2", + "@dicebear/notionists": "9.2.2", + "@dicebear/notionists-neutral": "9.2.2", + "@dicebear/open-peeps": "9.2.2", + "@dicebear/personas": "9.2.2", + "@dicebear/pixel-art": "9.2.2", + "@dicebear/pixel-art-neutral": "9.2.2", + "@dicebear/rings": "9.2.2", + "@dicebear/shapes": "9.2.2", + "@dicebear/thumbs": "9.2.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { - "@resvg/resvg-js": "^2.4.1", - "exiftool-vendored": "^23.0.0", - "sharp": "^0.32.6" - }, - "peerDependenciesMeta": { - "@resvg/resvg-js": { - "optional": true - }, - "exiftool-vendored": { - "optional": true - }, - "sharp": { - "optional": true - } + "@dicebear/core": "^9.0.0" } }, "node_modules/@dicebear/core": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@dicebear/core/-/core-8.0.2.tgz", - "integrity": "sha512-Zr3dBAH+6BBYc2kjz7KvJCMYasQlsY9CZ7D3abgZhk/XRT4B3qxo8kP+FL8YjJvrOJyV2P7h08BAKZlTWuKXPA==", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@dicebear/core/-/core-9.2.2.tgz", + "integrity": "sha512-ROhgHG249dPtcXgBHcqPEsDeAPRPRD/9d+tZCjLYyueO+cXDlIA8dUlxpwIVcOuZFvCyW6RJtqo8BhNAi16pIQ==", "dependencies": { - "@dicebear/converter": "8.0.2", "@types/json-schema": "^7.0.11" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, "node_modules/@dicebear/croodles": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@dicebear/croodles/-/croodles-8.0.2.tgz", - "integrity": "sha512-UKW6PKtID0P9pUlbTy3SRbhWghHbyIjoYK/rbp1Tq2jVRmES9mLGcpO4azpP/JgsC7btjLYN7BvyDzVp6Ob7aw==", - "license": "MIT", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@dicebear/croodles/-/croodles-9.2.2.tgz", + "integrity": "sha512-OzvAXQWsOgMwL3Sl+lBxCubqSOWoBJpC78c4TKnNTS21rR63TtXUyVdLLzgKVN4YHRnvMgtPf8F/W9YAgIDK4w==", "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { - "@dicebear/core": "^8.0.0" + "@dicebear/core": "^9.0.0" } }, "node_modules/@dicebear/croodles-neutral": { - "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", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@dicebear/croodles-neutral/-/croodles-neutral-9.2.2.tgz", + "integrity": "sha512-/4mNirxoQ+z1kHXnpDRbJ1JV1ZgXogeTeNp0MaFYxocCgHfJ7ckNM23EE1I7akoo9pqPxrKlaeNzGAjKHdS9vA==", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@dicebear/core": "^9.0.0" + } + }, + "node_modules/@dicebear/dylan": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@dicebear/dylan/-/dylan-9.2.2.tgz", + "integrity": "sha512-s7e3XliC1YXP+Wykj+j5kwdOWFRXFzYHYk/PB4oZ1F3sJandXiG0HS4chaNu4EoP0yZgKyFMUVTGZx+o6tMaYg==", "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { - "@dicebear/core": "^8.0.0" + "@dicebear/core": "^9.0.0" } }, "node_modules/@dicebear/fun-emoji": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@dicebear/fun-emoji/-/fun-emoji-8.0.2.tgz", - "integrity": "sha512-F0GrSJTgfV5sKlXCuZ5fQFTkeAv10301rZjAN6nxdxEtaG3iM1NnGpVFnPYtyl/dyHNsTgRuzNz8g0qrDuMQLw==", - "license": "MIT", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@dicebear/fun-emoji/-/fun-emoji-9.2.2.tgz", + "integrity": "sha512-M+rYTpB3lfwz18f+/i+ggNwNWUoEj58SJqXJ1wr7Jh/4E5uL+NmJg9JGwYNaVtGbCFrKAjSaILNUWGQSFgMfog==", "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + }, + "peerDependencies": { + "@dicebear/core": "^9.0.0" + } + }, + "node_modules/@dicebear/glass": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@dicebear/glass/-/glass-9.2.2.tgz", + "integrity": "sha512-imCMxcg+XScHYtQq2MUv1lCzhQSCUglMlPSezKEpXhTxgbgUpmGlSGVkOfmX5EEc7SQowKkF1W/1gNk6CXvBaQ==", + "engines": { + "node": ">=18.0.0" }, "peerDependencies": { - "@dicebear/core": "^8.0.0" + "@dicebear/core": "^9.0.0" } }, "node_modules/@dicebear/icons": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@dicebear/icons/-/icons-8.0.2.tgz", - "integrity": "sha512-UAtAcsxSFxM6YtQFkMhu0/Xvk3tP/WA0OdZ0TZZdqCIldK5dzKFsiiixa3hwLQd9AB1SyJmHAL4XVrpkWF0ijQ==", - "license": "MIT", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@dicebear/icons/-/icons-9.2.2.tgz", + "integrity": "sha512-Tqq2OVCdS7J02DNw58xwlgLGl40sWEckbqXT3qRvIF63FfVq+wQZBGuhuiyAURcSgvsc3h2oQeYFi9iXh7HTOA==", "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { - "@dicebear/core": "^8.0.0" + "@dicebear/core": "^9.0.0" } }, "node_modules/@dicebear/identicon": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@dicebear/identicon/-/identicon-8.0.2.tgz", - "integrity": "sha512-4ZejuMquE5XnN41XxZ+Tpssfv4pbFQcCFyXvDPsQv6rLT9WSj/JEXUgVNRNQSHwDEh+UzR01l5JtzOrQhw1hDw==", - "license": "MIT", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@dicebear/identicon/-/identicon-9.2.2.tgz", + "integrity": "sha512-POVKFulIrcuZf3rdAgxYaSm2XUg/TJg3tg9zq9150reEGPpzWR7ijyJ03dzAADPzS3DExfdYVT9+z3JKwwJnTQ==", "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { - "@dicebear/core": "^8.0.0" + "@dicebear/core": "^9.0.0" } }, "node_modules/@dicebear/initials": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@dicebear/initials/-/initials-8.0.2.tgz", - "integrity": "sha512-wVknmFQiCdpNgM/a0Szh3LLOJU4zK5xyzIRHejJ2KyBx2WtDfiNZjgeDM9kjg/QGWk3t3cql4ZLlzqn2DHVcEA==", - "license": "MIT", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@dicebear/initials/-/initials-9.2.2.tgz", + "integrity": "sha512-/xNnsEmsstWjmF77htAOuwOMhFlP6eBVXgcgFlTl/CCH/Oc6H7t0vwX1he8KLQBBzjGpvJcvIAn4Wh9rE4D5/A==", "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { - "@dicebear/core": "^8.0.0" + "@dicebear/core": "^9.0.0" } }, "node_modules/@dicebear/lorelei": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@dicebear/lorelei/-/lorelei-8.0.2.tgz", - "integrity": "sha512-Gi/f+QWfWYZD90h9QNPkmFM6iNrp+vD8LMmapH8DQBIIV5gEaHB0AQ54y0kCqnWbv0597E6rwPkdDGO4fuEVJw==", - "license": "MIT", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@dicebear/lorelei/-/lorelei-9.2.2.tgz", + "integrity": "sha512-koXqVr/vcWUPo00VP5H6Czsit+uF1tmwd2NK7Q/e34/9Sd1f4QLLxHjjBNm/iNjCI1+UNTOvZ2Qqu0N5eo7Flw==", "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { - "@dicebear/core": "^8.0.0" + "@dicebear/core": "^9.0.0" } }, "node_modules/@dicebear/lorelei-neutral": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@dicebear/lorelei-neutral/-/lorelei-neutral-8.0.2.tgz", - "integrity": "sha512-cENa3xII5mnJ88Y61AHLTOJhhnxtFX4a/cSJ6XapwkjUVTKkNLDGWKinC6bw7A3AWFTUf2MmOg3kVlFtX6ExeQ==", - "license": "MIT", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@dicebear/lorelei-neutral/-/lorelei-neutral-9.2.2.tgz", + "integrity": "sha512-Eys9Os6nt2Xll7Mvu66CfRR2YggTopWcmFcRZ9pPdohS96kT0MsLI2iTcfZXQ51K8hvT3IbwoGc86W8n0cDxAQ==", "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { - "@dicebear/core": "^8.0.0" + "@dicebear/core": "^9.0.0" } }, "node_modules/@dicebear/micah": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@dicebear/micah/-/micah-8.0.2.tgz", - "integrity": "sha512-H7YYdZbvWGJGBsPgmrPQuxWp/OMUff/Y70tE+comR6bGjIJyGM9hoTNBviflaC2INK9c0ieUCmvo185axxHVfQ==", - "license": "MIT", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@dicebear/micah/-/micah-9.2.2.tgz", + "integrity": "sha512-NCajcJV5yw8uMKiACp694w1T/UyYme2CUEzyTzWHgWnQ+drAuCcH8gpAoLWd67viNdQB/MTpNlaelUgTjmI4AQ==", "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { - "@dicebear/core": "^8.0.0" + "@dicebear/core": "^9.0.0" } }, "node_modules/@dicebear/miniavs": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@dicebear/miniavs/-/miniavs-8.0.2.tgz", - "integrity": "sha512-xjuZUS7tBeWjbzGlGmgLh6gbIQLQ8TJQyeP0+Pal0bQxzhufxT452v4vAw38Meuz94B5Mm6VR+9bQjr10fd8eQ==", - "license": "MIT", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@dicebear/miniavs/-/miniavs-9.2.2.tgz", + "integrity": "sha512-vvkWXttdw+KHF3j+9qcUFzK+P0nbNnImGjvN48wwkPIh2h08WWFq0MnoOls4IHwUJC4GXBjWtiyVoCxz6hhtOA==", "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { - "@dicebear/core": "^8.0.0" + "@dicebear/core": "^9.0.0" } }, "node_modules/@dicebear/notionists": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@dicebear/notionists/-/notionists-8.0.2.tgz", - "integrity": "sha512-XLG85pKqW32M92zI0Aw8Hg1pE2+lAn9hs7zEwGsud2sCamQeE8jZWuWBZ89ktizWiZVzNMlHNUuMmxGoiHNlqg==", - "license": "MIT", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@dicebear/notionists/-/notionists-9.2.2.tgz", + "integrity": "sha512-Z9orRaHoj7Y9Ap4wEu8XOrFACsG1KbbBQUPV1R50uh6AHwsyNrm4cS84ICoGLvxgLNHHOae3YCjd8aMu2z19zg==", "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { - "@dicebear/core": "^8.0.0" + "@dicebear/core": "^9.0.0" } }, "node_modules/@dicebear/notionists-neutral": { - "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", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@dicebear/notionists-neutral/-/notionists-neutral-9.2.2.tgz", + "integrity": "sha512-AhOzk+lz6kB4uxGun8AJhV+W1nttnMlxmxd+5KbQ/txCIziYIaeD3il44wsAGegEpGFvAZyMYtR/jjfHcem3TA==", "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { - "@dicebear/core": "^8.0.0" + "@dicebear/core": "^9.0.0" } }, "node_modules/@dicebear/open-peeps": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@dicebear/open-peeps/-/open-peeps-8.0.2.tgz", - "integrity": "sha512-fZb4C6mkZpp70tRWcogPS1PZGF0k3pclXswXhGKBdL1g0ULr157BCXBlx9juCOZ2K8w6teLQ5VE/uP490ddPUw==", - "license": "MIT", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@dicebear/open-peeps/-/open-peeps-9.2.2.tgz", + "integrity": "sha512-6PeQDHYyjvKrGSl/gP+RE5dSYAQGKpcGnM65HorgyTIugZK7STo0W4hvEycedupZ3MCCEH8x/XyiChKM2sHXog==", "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { - "@dicebear/core": "^8.0.0" + "@dicebear/core": "^9.0.0" } }, "node_modules/@dicebear/personas": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@dicebear/personas/-/personas-8.0.2.tgz", - "integrity": "sha512-8Xe4gaO/uJTwOMFBQv9AXJa0G8gzmqRtiH9UDrhs0yNF5Hh4g2yOeoefRBbLP/SuU5zSSHIZpcHKQD9Q1C30tA==", - "license": "MIT", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@dicebear/personas/-/personas-9.2.2.tgz", + "integrity": "sha512-705+ObNLC0w1fcgE/Utav+8bqO+Esu53TXegpX5j7trGEoIMf2bThqJGHuhknZ3+T2az3Wr89cGyOGlI0KLzLA==", "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { - "@dicebear/core": "^8.0.0" + "@dicebear/core": "^9.0.0" } }, "node_modules/@dicebear/pixel-art": { - "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", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@dicebear/pixel-art/-/pixel-art-9.2.2.tgz", + "integrity": "sha512-BvbFdrpzQl04+Y9UsWP63YGug+ENGC7GMG88qbEFWxb/IqRavGa4H3D0T4Zl2PSLiw7f2Ctv98bsCQZ1PtCznQ==", "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { - "@dicebear/core": "^8.0.0" + "@dicebear/core": "^9.0.0" } }, "node_modules/@dicebear/pixel-art-neutral": { - "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", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@dicebear/pixel-art-neutral/-/pixel-art-neutral-9.2.2.tgz", + "integrity": "sha512-CdUY77H6Aj7dKLW3hdkv7tu0XQJArUjaWoXihQxlhl3oVYplWaoyu9omYy5pl8HTqs8YgVTGljjMXYoFuK0JUw==", "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { - "@dicebear/core": "^8.0.0" + "@dicebear/core": "^9.0.0" } }, "node_modules/@dicebear/rings": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@dicebear/rings/-/rings-8.0.2.tgz", - "integrity": "sha512-aCyTiYo8nGzUjJ8PD0ctErcvbKe1UEaeWHvKcQERLDX8WLQMykBJquFodhNgN97TjZ8+8ur+vsrR+g8B9Z0zDw==", - "license": "MIT", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@dicebear/rings/-/rings-9.2.2.tgz", + "integrity": "sha512-eD1J1k364Arny+UlvGrk12HP/XGG6WxPSm4BarFqdJGSV45XOZlwqoi7FlcMr9r9yvE/nGL8OizbwMYusEEdjw==", "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { - "@dicebear/core": "^8.0.0" + "@dicebear/core": "^9.0.0" } }, "node_modules/@dicebear/shapes": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@dicebear/shapes/-/shapes-8.0.2.tgz", - "integrity": "sha512-5GaeUP8QkC7yuUutQCGiMH2U7ditdpKxfRjzlSG9uqaWV/RZZ0u190POawHIu7VpsuHWzMBRV9yu1l7Lc7wQFg==", - "license": "MIT", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@dicebear/shapes/-/shapes-9.2.2.tgz", + "integrity": "sha512-e741NNWBa7fg0BjomxXa0fFPME2XCIR0FA+VHdq9AD2taTGHEPsg5x1QJhCRdK6ww85yeu3V3ucpZXdSrHVw5Q==", "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { - "@dicebear/core": "^8.0.0" + "@dicebear/core": "^9.0.0" } }, "node_modules/@dicebear/thumbs": { - "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", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@dicebear/thumbs/-/thumbs-9.2.2.tgz", + "integrity": "sha512-FkPLDNu7n5kThLSk7lR/0cz/NkUqgGdZGfLZv6fLkGNGtv6W+e2vZaO7HCXVwIgJ+II+kImN41zVIZ6Jlll7pQ==", "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { - "@dicebear/core": "^8.0.0" + "@dicebear/core": "^9.0.0" } }, "node_modules/@emotion/babel-plugin": { @@ -2699,14 +2668,14 @@ } }, "node_modules/@emotion/serialize": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.1.tgz", - "integrity": "sha512-dEPNKzBPU+vFPGa+z3axPRn8XVDetYORmDC0wAiej+TNcOZE70ZMJa0X7JdeoM6q/nWTMZeLpN/fTnD9o8MQBA==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.2.tgz", + "integrity": "sha512-grVnMvVPK9yUVE6rkKfAJlYZgo0cu3l9iMC77V7DW6E1DUIrU68pSEXRmFZFOFB1QFo57TncmOcvcbMDWsL4yA==", "dependencies": { "@emotion/hash": "^0.9.2", "@emotion/memoize": "^0.9.0", "@emotion/unitless": "^0.10.0", - "@emotion/utils": "^1.4.0", + "@emotion/utils": "^1.4.1", "csstype": "^3.0.2" } }, @@ -2753,10 +2722,9 @@ } }, "node_modules/@emotion/utils": { - "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" + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.1.tgz", + "integrity": "sha512-BymCXzCG3r72VKJxaYVwOXATqXIZ85cuvg0YOUDxMGNrKc1DJRZk8MgV5wyXRyEayIMd4FuXJIUgTBXvDNW5cA==" }, "node_modules/@emotion/weak-memoize": { "version": "0.4.0", @@ -2764,3786 +2732,6868 @@ "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", "license": "MIT" }, - "node_modules/@esbuild/win32-x64": { + "node_modules/@esbuild/aix-ppc64": { "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", "cpu": [ - "x64" + "ppc64" ], "optional": true, "os": [ - "win32" + "aix" ], "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==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + "node": ">=12" } }, - "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, - "license": "MIT", + "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" + ], + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + "node": ">=12" } }, - "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, - "license": "MIT", - "peer": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, + "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" + ], + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=12" } }, - "node_modules/@eslint/eslintrc/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, - "license": "MIT", - "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" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "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" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" } }, - "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==", - "dev": true, - "license": "Python-2.0", - "peer": true - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "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" - }, + "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" + ], + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=12" } }, - "node_modules/@eslint/eslintrc/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, - "license": "MIT", - "peer": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "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" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" } }, - "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==", - "dev": true, - "license": "MIT", - "peer": true + "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" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } }, - "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, + "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" + ], + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=12" } }, - "node_modules/@eslint/js": { - "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, + "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" + ], + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=12" } }, - "node_modules/@floating-ui/core": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.1.tgz", - "integrity": "sha512-42UH54oPZHPdRHdw6BgoBD6cg/eVTmVrFcgeRDM3jbO7uxSoipVcmcIGFcA5jmOHO5apcyvBhkSKES3fQJnu7A==", - "dependencies": { - "@floating-ui/utils": "^0.2.0" + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "node_modules/@floating-ui/dom": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.4.tgz", - "integrity": "sha512-0G8R+zOvQsAG1pg2Q99P21jiqxqGBW1iRe/iXHsBRBxnpXKFI8QwbB4x5KmYLggNO5m34IQgOIu9SCRfR/WWiQ==", - "dependencies": { - "@floating-ui/core": "^1.0.0", - "@floating-ui/utils": "^0.2.0" + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "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/@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" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "node_modules/@floating-ui/react-dom": { - "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" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" + "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" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "node_modules/@floating-ui/utils": { - "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/@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" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } }, - "node_modules/@graphql-typed-document-node/core": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.2.0.tgz", - "integrity": "sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==", - "peerDependencies": { - "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + "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" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "node_modules/@humanwhocodes/config-array": { - "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": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, + "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" + ], + "optional": true, + "os": [ + "netbsd" + ], "engines": { - "node": ">=10.10.0" + "node": ">=12" } }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.1.tgz", + "integrity": "sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==", + "cpu": [ + "arm64" + ], "dev": true, - "peer": true, + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "node": ">=18" } }, - "node_modules/@humanwhocodes/object-schema": { - "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", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, + "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" + ], + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, + "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" + ], + "optional": true, + "os": [ + "sunos" + ], "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, + "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" + ], + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/@jedmao/location": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@jedmao/location/-/location-3.0.0.tgz", - "integrity": "sha512-p7mzNlgJbCioUYLUEKds3cQG4CHONVFJNYqMe6ocEtENCL/jYmMo1Q3ApwsMmU+L0ZkaDJEyv4HokaByLoPwlQ==", - "dev": true + "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" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } }, - "node_modules/@jest/console": { - "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": "*", - "chalk": "^4.0.0", - "jest-message-util": "^27.5.1", - "jest-util": "^27.5.1", - "slash": "^3.0.0" - }, + "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" + ], + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=12" } }, - "node_modules/@jest/console/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "eslint-visitor-keys": "^3.3.0" }, "engines": { - "node": ">=10" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@jest/core": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.5.1.tgz", - "integrity": "sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==", + "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, - "dependencies": { - "@jest/console": "^27.5.1", - "@jest/reporters": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.8.1", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^27.5.1", - "jest-config": "^27.5.1", - "jest-haste-map": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-resolve-dependencies": "^27.5.1", - "jest-runner": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", - "jest-watcher": "^27.5.1", - "micromatch": "^4.0.4", - "rimraf": "^3.0.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, + "license": "MIT", "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" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@jest/core/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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, + "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" }, "engines": { - "node": ">=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/environment": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", - "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", + "node_modules/@eslint/eslintrc/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, + "license": "MIT", "dependencies": { - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "jest-mock": "^27.5.1" + "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.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@jest/fake-timers": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", - "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", + "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==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/types": "^27.5.1", - "@sinonjs/fake-timers": "^8.0.1", - "@types/node": "*", - "jest-message-util": "^27.5.1", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.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/globals": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz", - "integrity": "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==", + "node_modules/@eslint/eslintrc/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, + "license": "MIT", "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/types": "^27.5.1", - "expect": "^27.5.1" + "argparse": "^2.0.1" }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/@jest/reporters": { - "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", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.2", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-haste-map": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-util": "^27.5.1", - "jest-worker": "^27.5.1", - "slash": "^3.0.0", - "source-map": "^0.6.0", - "string-length": "^4.0.1", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^8.1.0" - }, - "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" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } + "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==", + "dev": true, + "license": "MIT" }, - "node_modules/@jest/reporters/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@jest/reporters/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/js": { + "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", "engines": { - "node": ">=0.10.0" + "node": "^12.22.0 || ^14.17.0 || >=16.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, + "node_modules/@floating-ui/core": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.1.tgz", + "integrity": "sha512-42UH54oPZHPdRHdw6BgoBD6cg/eVTmVrFcgeRDM3jbO7uxSoipVcmcIGFcA5jmOHO5apcyvBhkSKES3fQJnu7A==", "dependencies": { - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9", - "source-map": "^0.6.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "@floating-ui/utils": "^0.2.0" } }, - "node_modules/@jest/source-map/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" + "node_modules/@floating-ui/dom": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.4.tgz", + "integrity": "sha512-0G8R+zOvQsAG1pg2Q99P21jiqxqGBW1iRe/iXHsBRBxnpXKFI8QwbB4x5KmYLggNO5m34IQgOIu9SCRfR/WWiQ==", + "dependencies": { + "@floating-ui/core": "^1.0.0", + "@floating-ui/utils": "^0.2.0" } }, - "node_modules/@jest/test-result": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.5.1.tgz", - "integrity": "sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==", - "dev": true, + "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": { - "@jest/console": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" + "@floating-ui/react-dom": "^2.1.2", + "@floating-ui/utils": "^0.2.8", + "tabbable": "^6.0.0" }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" } }, - "node_modules/@jest/test-sequencer": { - "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, + "node_modules/@floating-ui/react-dom": { + "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": { - "@jest/test-result": "^27.5.1", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-runtime": "^27.5.1" + "@floating-ui/dom": "^1.0.0" }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" } }, - "node_modules/@jest/transform": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", - "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", + "node_modules/@floating-ui/utils": { + "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", + "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.2.0.tgz", + "integrity": "sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==", + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "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", "dependencies": { - "@babel/core": "^7.1.0", - "@jest/types": "^27.5.1", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-util": "^27.5.1", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "^3.0.0" + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=10.10.0" } }, - "node_modules/@jest/transform/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, "engines": { - "node": ">=10" + "node": ">=12.22" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@jest/transform/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/@humanwhocodes/object-schema": { + "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, - "engines": { - "node": ">=0.10.0" - } + "license": "BSD-3-Clause" }, - "node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, + "node_modules/@inquirer/checkbox": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-3.0.1.tgz", + "integrity": "sha512-0hm2nrToWUdD6/UHnel/UKGdk1//ke5zGUpHIvk5ZWmaKezlGxZkOJXNSWsdxO/rEqTkbB3lNC2J6nBElV2aAQ==", + "license": "MIT", "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" + "@inquirer/core": "^9.2.1", + "@inquirer/figures": "^1.0.6", + "@inquirer/type": "^2.0.0", + "ansi-escapes": "^4.3.2", + "yoctocolors-cjs": "^2.1.2" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=18" } }, - "node_modules/@jest/types/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, + "node_modules/@inquirer/confirm": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-4.0.1.tgz", + "integrity": "sha512-46yL28o2NJ9doViqOy0VDcoTzng7rAb6yPQKU7VDLqkmbCaH4JqK4yk4XqlzNWy9PVC5pG1ZUXPBQv+VqnYs2w==", + "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@inquirer/core": "^9.2.1", + "@inquirer/type": "^2.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=18" } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "node_modules/@inquirer/core": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.2.1.tgz", + "integrity": "sha512-F2VBt7W/mwqEU4bL0RnHNZmC/OxzNx9cOYxHqnXX3MP6ruYvZUZAW9imgN9+h/uBT/oP8Gh888J2OZSbjSeWcg==", + "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" + "@inquirer/figures": "^1.0.6", + "@inquirer/type": "^2.0.0", + "@types/mute-stream": "^0.0.4", + "@types/node": "^22.5.5", + "@types/wrap-ansi": "^3.0.0", + "ansi-escapes": "^4.3.2", + "cli-width": "^4.1.0", + "mute-stream": "^1.0.0", + "signal-exit": "^4.1.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.2" }, "engines": { - "node": ">=6.0.0" + "node": ">=18" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "engines": { - "node": ">=6.0.0" + "node_modules/@inquirer/core/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "node_modules/@inquirer/core/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, "engines": { - "node": ">=6.0.0" + "node": ">=8" } }, - "node_modules/@jridgewell/source-map": { - "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, + "node_modules/@inquirer/editor": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-3.0.1.tgz", + "integrity": "sha512-VA96GPFaSOVudjKFraokEEmUQg/Lub6OXvbIEZU1SDCmBzRkHGhxoFAVaF30nyiB4m5cEbDgiI2QRacXZ2hw9Q==", + "license": "MIT", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@inquirer/core": "^9.2.1", + "@inquirer/type": "^2.0.0", + "external-editor": "^3.1.0" + }, + "engines": { + "node": ">=18" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "node_modules/@inquirer/expand": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-3.0.1.tgz", + "integrity": "sha512-ToG8d6RIbnVpbdPdiN7BCxZGiHOTomOX94C2FaT5KOHupV40tKEDozp12res6cMIfRKrXLJyexAZhWVHgbALSQ==", + "license": "MIT", "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "@inquirer/core": "^9.2.1", + "@inquirer/type": "^2.0.0", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" } }, - "node_modules/@microsoft/tsdoc": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.15.0.tgz", - "integrity": "sha512-HZpPoABogPvjeJOdzCOSJsXeL/SMCBgBZMVC3X3d7YYp2gf31MfxhUoYUNwf1ERPJOnQc0wkFn9trqI6ZEdZuA==", - "dev": true + "node_modules/@inquirer/figures": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.9.tgz", + "integrity": "sha512-BXvGj0ehzrngHTPTDqUoDT3NXL8U0RxUk2zJm2A66RhCEIWdtU1v6GuUqNAgArW4PQ9CinqIWyHdQgdwOj06zQ==", + "license": "MIT", + "engines": { + "node": ">=18" + } }, - "node_modules/@microsoft/tsdoc-config": { - "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, + "node_modules/@inquirer/input": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-3.0.1.tgz", + "integrity": "sha512-BDuPBmpvi8eMCxqC5iacloWqv+5tQSJlUafYWUe31ow1BVXjW2a5qe3dh4X/Z25Wp22RwvcaLCc2siHobEOfzg==", + "license": "MIT", "dependencies": { - "@microsoft/tsdoc": "0.15.0", - "ajv": "~8.12.0", - "jju": "~1.4.0", - "resolve": "~1.22.2" + "@inquirer/core": "^9.2.1", + "@inquirer/type": "^2.0.0" + }, + "engines": { + "node": ">=18" } }, - "node_modules/@mui/base": { - "version": "5.0.0-beta.40", - "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.40.tgz", - "integrity": "sha512-I/lGHztkCzvwlXpjD2+SNmvNQvB4227xBXhISPjEaJUXGImOQ9f3D2Yj/T3KasSI/h0MLWy74X0J6clhPmsRbQ==", + "node_modules/@inquirer/number": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-2.0.1.tgz", + "integrity": "sha512-QpR8jPhRjSmlr/mD2cw3IR8HRO7lSVOnqUvQa8scv1Lsr3xoAMMworcYW3J13z3ppjBFBD2ef1Ci6AE5Qn8goQ==", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.23.9", - "@floating-ui/react-dom": "^2.0.8", - "@mui/types": "^7.2.14", - "@mui/utils": "^5.15.14", - "@popperjs/core": "^2.11.8", - "clsx": "^2.1.0", - "prop-types": "^15.8.1" + "@inquirer/core": "^9.2.1", + "@inquirer/type": "^2.0.0" }, "engines": { - "node": ">=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0", - "react-dom": "^17.0.0 || ^18.0.0" + "node": ">=18" + } + }, + "node_modules/@inquirer/password": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-3.0.1.tgz", + "integrity": "sha512-haoeEPUisD1NeE2IanLOiFr4wcTXGWrBOyAyPZi1FfLJuXOzNmxCJPgUrGYKVh+Y8hfGJenIfz5Wb/DkE9KkMQ==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^9.2.1", + "@inquirer/type": "^2.0.0", + "ansi-escapes": "^4.3.2" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "engines": { + "node": ">=18" } }, - "node_modules/@mui/core-downloads-tracker": { - "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/@inquirer/prompts": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-6.0.1.tgz", + "integrity": "sha512-yl43JD/86CIj3Mz5mvvLJqAOfIup7ncxfJ0Btnl0/v5TouVUyeEdcpknfgc+yMevS/48oH9WAkkw93m7otLb/A==", + "license": "MIT", + "dependencies": { + "@inquirer/checkbox": "^3.0.1", + "@inquirer/confirm": "^4.0.1", + "@inquirer/editor": "^3.0.1", + "@inquirer/expand": "^3.0.1", + "@inquirer/input": "^3.0.1", + "@inquirer/number": "^2.0.1", + "@inquirer/password": "^3.0.1", + "@inquirer/rawlist": "^3.0.1", + "@inquirer/search": "^2.0.1", + "@inquirer/select": "^3.0.1" + }, + "engines": { + "node": ">=18" } }, - "node_modules/@mui/icons-material": { - "version": "5.16.7", - "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.16.7.tgz", - "integrity": "sha512-UrGwDJCXEszbDI7yV047BYU5A28eGJ79keTCP4cc74WyncuVrnurlmIRxaHL8YK+LI1Kzq+/JM52IAkNnv4u+Q==", + "node_modules/@inquirer/rawlist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-3.0.1.tgz", + "integrity": "sha512-VgRtFIwZInUzTiPLSfDXK5jLrnpkuSOh1ctfaoygKAdPqjcjKYmGh6sCY1pb0aGnCGsmhUxoqLDUAU0ud+lGXQ==", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.23.9" + "@inquirer/core": "^9.2.1", + "@inquirer/type": "^2.0.0", + "yoctocolors-cjs": "^2.1.2" }, "engines": { - "node": ">=12.0.0" + "node": ">=18" + } + }, + "node_modules/@inquirer/search": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-2.0.1.tgz", + "integrity": "sha512-r5hBKZk3g5MkIzLVoSgE4evypGqtOannnB3PKTG9NRZxyFRKcfzrdxXXPcoJQsxJPzvdSU2Rn7pB7lw0GCmGAg==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^9.2.1", + "@inquirer/figures": "^1.0.6", + "@inquirer/type": "^2.0.0", + "yoctocolors-cjs": "^2.1.2" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/select": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-3.0.1.tgz", + "integrity": "sha512-lUDGUxPhdWMkN/fHy1Lk7pF3nK1fh/gqeyWXmctefhxLYxlDsc7vsPBEpxrfVGDsVdyYJsiJoD4bJ1b623cV1Q==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^9.2.1", + "@inquirer/figures": "^1.0.6", + "@inquirer/type": "^2.0.0", + "ansi-escapes": "^4.3.2", + "yoctocolors-cjs": "^2.1.2" }, - "peerDependencies": { - "@mui/material": "^5.0.0", - "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0" + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-2.0.0.tgz", + "integrity": "sha512-XvJRx+2KR3YXyYtPUUy+qd9i7p+GO9Ko6VIIpWlBrpWwXDv8WLFeHTxz35CfQFUiBMLXlGHhGzys7lqit9gWag==", + "license": "MIT", + "dependencies": { + "mute-stream": "^1.0.0" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "engines": { + "node": ">=18" } }, - "node_modules/@mui/material": { - "version": "5.16.7", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.16.7.tgz", - "integrity": "sha512-cwwVQxBhK60OIOqZOVLFt55t01zmarKJiJUWbk0+8s/Ix5IaUzAShqlJchxsIQ4mSrWqgcKCCXKtIlG5H+/Jmg==", + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, "dependencies": { - "@babel/runtime": "^7.23.9", - "@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.3.1", - "react-transition-group": "^4.4.5" + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" }, "engines": { - "node": ">=12.0.0" + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "engines": { + "node": ">=12" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "@emotion/react": "^11.5.0", - "@emotion/styled": "^11.3.0", - "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0", - "react-dom": "^17.0.0 || ^18.0.0" + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/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": ">=12" }, - "peerDependenciesMeta": { - "@emotion/react": { - "optional": true - }, - "@emotion/styled": { - "optional": true - }, - "@types/react": { - "optional": true - } + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@mui/private-theming": { - "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==", + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, "dependencies": { - "@babel/runtime": "^7.23.9", - "@mui/utils": "^5.16.6", - "prop-types": "^15.8.1" + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=12.0.0" + "node": ">=12" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@mui/styled-engine": { - "version": "5.16.6", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.16.6.tgz", - "integrity": "sha512-zaThmS67ZmtHSWToTiHslbI8jwrmITcN93LQaR2lKArbvS7Z3iLkwRoiikNWutx9MBs8Q6okKvbZq1RQYB3v7g==", + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, "dependencies": { - "@babel/runtime": "^7.23.9", - "@emotion/cache": "^11.11.0", - "csstype": "^3.1.3", - "prop-types": "^15.8.1" + "ansi-regex": "^6.0.1" }, "engines": { - "node": ">=12.0.0" + "node": ">=12" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "@emotion/react": "^11.4.1", - "@emotion/styled": "^11.3.0", - "react": "^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@emotion/react": { - "optional": true - }, - "@emotion/styled": { - "optional": true - } + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/@mui/system": { - "version": "5.16.7", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.16.7.tgz", - "integrity": "sha512-Jncvs/r/d/itkxh7O7opOunTqbbSSzMTHzZkNLM+FjAOg+cYAZHrPDlYe1ZGKUYORwwb2XexlWnpZp0kZ4AHuA==", + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, "dependencies": { - "@babel/runtime": "^7.23.9", - "@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" + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=12.0.0" + "node": ">=12" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "@emotion/react": "^11.5.0", - "@emotion/styled": "^11.3.0", - "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0" + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" }, - "peerDependenciesMeta": { - "@emotion/react": { - "optional": true - }, - "@emotion/styled": { - "optional": true - }, - "@types/react": { - "optional": true - } + "engines": { + "node": ">=8" } }, - "node_modules/@mui/types": { - "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" + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jedmao/location": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@jedmao/location/-/location-3.0.0.tgz", + "integrity": "sha512-p7mzNlgJbCioUYLUEKds3cQG4CHONVFJNYqMe6ocEtENCL/jYmMo1Q3ApwsMmU+L0ZkaDJEyv4HokaByLoPwlQ==", + "dev": true + }, + "node_modules/@jest/console": { + "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": "*", + "chalk": "^4.0.0", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", + "slash": "^3.0.0" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/@mui/utils": { - "version": "5.16.6", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.16.6.tgz", - "integrity": "sha512-tWiQqlhxAt3KENNiSRL+DIn9H5xNVK6Jjf70x3PnfQPz1MPBdh7yyIcAyVBT9xiw7hP3SomRhPR7hzBMBCjqEA==", + "node_modules/@jest/console/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, "dependencies": { - "@babel/runtime": "^7.23.9", - "@mui/types": "^7.2.15", - "@types/prop-types": "^15.7.12", - "clsx": "^2.1.1", - "prop-types": "^15.8.1", - "react-is": "^18.3.1" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=12.0.0" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@mui/x-charts": { - "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==", + "node_modules/@jest/core": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.5.1.tgz", + "integrity": "sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==", + "dev": true, "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", - "prop-types": "^15.8.1" + "@jest/console": "^27.5.1", + "@jest/reporters": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^27.5.1", + "jest-config": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-resolve-dependencies": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "jest-watcher": "^27.5.1", + "micromatch": "^4.0.4", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=14.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" }, "peerDependencies": { - "@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-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" }, "peerDependenciesMeta": { - "@emotion/react": { - "optional": true - }, - "@emotion/styled": { + "node-notifier": { "optional": true } } }, - "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==", + "node_modules/@jest/core/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, "dependencies": { - "@babel/runtime": "^7.25.6", - "@mui/utils": "^5.16.6" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=14.0.0" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "react": "^17.0.0 || ^18.0.0" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@mui/x-data-grid": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@mui/x-data-grid/-/x-data-grid-7.16.0.tgz", - "integrity": "sha512-71ZyffTeF8RPa399UkMlUbQ8T70kOrUK3fBXfinnal4mwgISlKwBN8EHNZZhyxSQ4vpWs3wHrHZ6MGQeXNUhJQ==", + "node_modules/@jest/environment": { + "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": { - "@babel/runtime": "^7.25.6", - "@mui/utils": "^5.16.6", - "@mui/x-internals": "7.16.0", - "clsx": "^2.1.1", - "prop-types": "^15.8.1", - "reselect": "^5.1.1" + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1" }, "engines": { - "node": ">=14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "@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": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "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", + "@types/node": "*", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" }, - "peerDependenciesMeta": { - "@emotion/react": { - "optional": true - }, - "@emotion/styled": { - "optional": true - } + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/@mui/x-date-pickers": { - "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", - "@mui/system": "^5.15.15", - "@mui/utils": "^5.15.14", - "@types/react-transition-group": "^4.4.10", - "clsx": "^2.1.1", - "prop-types": "^15.8.1", - "react-transition-group": "^4.4.5" + "node_modules/@jest/globals": { + "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", + "expect": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/reporters": { + "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", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.2", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-haste-map": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "slash": "^3.0.0", + "source-map": "^0.6.0", + "string-length": "^4.0.1", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^8.1.0" + }, + "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" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/reporters/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/reporters/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@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", + "source-map": "^0.6.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/source-map/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@jest/test-result": { + "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", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "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", + "jest-haste-map": "^27.5.1", + "jest-runtime": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/transform": { + "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", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-util": "^27.5.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/transform/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/transform/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@jest/types": { + "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", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/types/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.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" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@kurkle/color": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz", + "integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==", + "license": "MIT" + }, + "node_modules/@microsoft/tsdoc": { + "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.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.15.0", + "ajv": "~8.12.0", + "jju": "~1.4.0", + "resolve": "~1.22.2" + } + }, + "node_modules/@mui/base": { + "version": "5.0.0-beta.61", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.61.tgz", + "integrity": "sha512-YaMOTXS3ecDNGsPKa6UdlJ8loFLvcL9+VbpCK3hfk71OaNauZRp4Yf7KeXDYr7Ms3M/XBD3SaiR6JMr6vYtfDg==", + "dependencies": { + "@babel/runtime": "^7.26.0", + "@floating-ui/react-dom": "^2.1.1", + "@mui/types": "^7.2.19", + "@mui/utils": "^6.1.6", + "@popperjs/core": "^2.11.8", + "clsx": "^2.1.1", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/core-downloads-tracker": { + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.1.6.tgz", + "integrity": "sha512-nz1SlR9TdBYYPz4qKoNasMPRiGb4PaIHFkzLzhju0YVYS5QSuFF2+n7CsiHMIDcHv3piPu/xDWI53ruhOqvZwQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + } + }, + "node_modules/@mui/icons-material": { + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-6.1.6.tgz", + "integrity": "sha512-5r9urIL2lxXb/sPN3LFfFYEibsXJUb986HhhIeu1gOcte460pwdSiEhBSxkAuyT8Dj7jvu9MjqSBmSumQELo8A==", + "dependencies": { + "@babel/runtime": "^7.26.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@mui/material": "^6.1.6", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/material": { + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-6.1.6.tgz", + "integrity": "sha512-1yvejiQ/601l5AK3uIdUlAVElyCxoqKnl7QA+2oFB/2qYPWfRwDgavW/MoywS5Y2gZEslcJKhe0s2F3IthgFgw==", + "dependencies": { + "@babel/runtime": "^7.26.0", + "@mui/core-downloads-tracker": "^6.1.6", + "@mui/system": "^6.1.6", + "@mui/types": "^7.2.19", + "@mui/utils": "^6.1.6", + "@popperjs/core": "^2.11.8", + "@types/react-transition-group": "^4.4.11", + "clsx": "^2.1.1", + "csstype": "^3.1.3", + "prop-types": "^15.8.1", + "react-is": "^18.3.1", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@mui/material-pigment-css": "^6.1.6", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@mui/material-pigment-css": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/private-theming": { + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.1.6.tgz", + "integrity": "sha512-ioAiFckaD/fJSnTrUMWgjl9HYBWt7ixCh7zZw7gDZ+Tae7NuprNV6QJK95EidDT7K0GetR2rU3kAeIR61Myttw==", + "dependencies": { + "@babel/runtime": "^7.26.0", + "@mui/utils": "^6.1.6", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/styled-engine": { + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.1.6.tgz", + "integrity": "sha512-I+yS1cSuSvHnZDBO7e7VHxTWpj+R7XlSZvTC4lS/OIbUNJOMMSd3UDP6V2sfwzAdmdDNBi7NGCRv2SZ6O9hGDA==", + "dependencies": { + "@babel/runtime": "^7.26.0", + "@emotion/cache": "^11.13.1", + "@emotion/serialize": "^1.3.2", + "@emotion/sheet": "^1.4.0", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.4.1", + "@emotion/styled": "^11.3.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/system": { + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-6.1.6.tgz", + "integrity": "sha512-qOf1VUE9wK8syiB0BBCp82oNBAVPYdj4Trh+G1s+L+ImYiKlubWhhqlnvWt3xqMevR+D2h1CXzA1vhX2FvA+VQ==", + "dependencies": { + "@babel/runtime": "^7.26.0", + "@mui/private-theming": "^6.1.6", + "@mui/styled-engine": "^6.1.6", + "@mui/types": "^7.2.19", + "@mui/utils": "^6.1.6", + "clsx": "^2.1.1", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/types": { + "version": "7.2.19", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.19.tgz", + "integrity": "sha512-6XpZEM/Q3epK9RN8ENoXuygnqUQxE+siN/6rGRi2iwJPgBUR25mphYQ9ZI87plGh58YoZ5pp40bFvKYOCDJ3tA==", + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils": { + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.1.6.tgz", + "integrity": "sha512-sBS6D9mJECtELASLM+18WUcXF6RH3zNxBRFeyCRg8wad6NbyNrdxLuwK+Ikvc38sTZwBzAz691HmSofLqHd9sQ==", + "dependencies": { + "@babel/runtime": "^7.26.0", + "@mui/types": "^7.2.19", + "@types/prop-types": "^15.7.13", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "react-is": "^18.3.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/x-charts": { + "version": "7.22.2", + "resolved": "https://registry.npmjs.org/@mui/x-charts/-/x-charts-7.22.2.tgz", + "integrity": "sha512-0Y2du4Ed7gOT53l8vVJ4vKT+Jz4Dh/iHnLy8TtL3+XhbPH9Ndu9Q30WwyyzOn84yt37hSUru/njQ1BWaSvVPHw==", + "dependencies": { + "@babel/runtime": "^7.25.7", + "@mui/utils": "^5.16.6 || ^6.0.0", + "@mui/x-charts-vendor": "7.20.0", + "@mui/x-internals": "7.21.0", + "@react-spring/rafz": "^9.7.5", + "@react-spring/web": "^9.7.5", + "clsx": "^2.1.1", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@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" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/x-charts-vendor": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@mui/x-charts-vendor/-/x-charts-vendor-7.20.0.tgz", + "integrity": "sha512-pzlh7z/7KKs5o0Kk0oPcB+sY0+Dg7Q7RzqQowDQjpy5Slz6qqGsgOB5YUzn0L+2yRmvASc4Pe0914Ao3tMBogg==", + "dependencies": { + "@babel/runtime": "^7.25.7", + "@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-data-grid": { + "version": "7.22.1", + "resolved": "https://registry.npmjs.org/@mui/x-data-grid/-/x-data-grid-7.22.1.tgz", + "integrity": "sha512-YHF96MEv7ACG/VuiycZjEAPH7cZLNuV2+bi/MyR1t/e6E6LTolYFykvjSFq+Imz1mYbW4+9mEvrHZsIKL5KKIQ==", + "dependencies": { + "@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": "^5.1.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@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" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/x-date-pickers": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-7.18.0.tgz", + "integrity": "sha512-12tXIoMj9vpS8fS/bS3kWPCoVrH38vNGCxgplI0vOnUrN9rJuYJz3agLPJe1S0xciTw+9W8ZSe3soaW+owoz1Q==", + "dependencies": { + "@babel/runtime": "^7.25.6", + "@mui/utils": "^5.16.6", + "@mui/x-internals": "7.18.0", + "@types/react-transition-group": "^4.4.11", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.9.0", + "@emotion/styled": "^11.8.1", + "@mui/material": "^5.15.14 || ^6.0.0", + "@mui/system": "^5.15.14 || ^6.0.0", + "date-fns": "^2.25.0 || ^3.2.0 || ^4.0.0", + "date-fns-jalali": "^2.13.0-0 || ^3.2.0-0", + "dayjs": "^1.10.7", + "luxon": "^3.0.2", + "moment": "^2.29.4", + "moment-hijri": "^2.1.2", + "moment-jalaali": "^0.7.4 || ^0.8.0 || ^0.9.0 || ^0.10.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "date-fns": { + "optional": true + }, + "date-fns-jalali": { + "optional": true + }, + "dayjs": { + "optional": true + }, + "luxon": { + "optional": true + }, + "moment": { + "optional": true + }, + "moment-hijri": { + "optional": true + }, + "moment-jalaali": { + "optional": true + } + } + }, + "node_modules/@mui/x-date-pickers/node_modules/@mui/utils": { + "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", + "@mui/types": "^7.2.15", + "@types/prop-types": "^15.7.12", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "react-is": "^18.3.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/x-date-pickers/node_modules/@mui/x-internals": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-7.18.0.tgz", + "integrity": "sha512-lzCHOWIR0cAIY1bGrWSprYerahbnH5C31ql/2OWCEjcngL2NAV1M6oKI2Vp4HheqzJ822c60UyWyapvyjSzY/A==", + "dependencies": { + "@babel/runtime": "^7.25.6", + "@mui/utils": "^5.16.6" + }, + "engines": { + "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-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": { + "@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==", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@parcel/watcher": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.0.tgz", + "integrity": "sha512-i0GV1yJnm2n3Yq1qw6QrUrd/LI9bE8WEBOTtOkpCXHHdyN3TAGgqAK/DAT05z4fq2x04cARXt2pDmjWjL92iTQ==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.0", + "@parcel/watcher-darwin-arm64": "2.5.0", + "@parcel/watcher-darwin-x64": "2.5.0", + "@parcel/watcher-freebsd-x64": "2.5.0", + "@parcel/watcher-linux-arm-glibc": "2.5.0", + "@parcel/watcher-linux-arm-musl": "2.5.0", + "@parcel/watcher-linux-arm64-glibc": "2.5.0", + "@parcel/watcher-linux-arm64-musl": "2.5.0", + "@parcel/watcher-linux-x64-glibc": "2.5.0", + "@parcel/watcher-linux-x64-musl": "2.5.0", + "@parcel/watcher-win32-arm64": "2.5.0", + "@parcel/watcher-win32-ia32": "2.5.0", + "@parcel/watcher-win32-x64": "2.5.0" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.0.tgz", + "integrity": "sha512-qlX4eS28bUcQCdribHkg/herLe+0A9RyYC+mm2PXpncit8z5b3nSqGVzMNR3CmtAOgRutiZ02eIJJgP/b1iEFQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.0.tgz", + "integrity": "sha512-hyZ3TANnzGfLpRA2s/4U1kbw2ZI4qGxaRJbBH2DCSREFfubMswheh8TeiC1sGZ3z2jUf3s37P0BBlrD3sjVTUw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.0.tgz", + "integrity": "sha512-9rhlwd78saKf18fT869/poydQK8YqlU26TMiNg7AIu7eBp9adqbJZqmdFOsbZ5cnLp5XvRo9wcFmNHgHdWaGYA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.0.tgz", + "integrity": "sha512-syvfhZzyM8kErg3VF0xpV8dixJ+RzbUaaGaeb7uDuz0D3FK97/mZ5AJQ3XNnDsXX7KkFNtyQyFrXZzQIcN49Tw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.0.tgz", + "integrity": "sha512-0VQY1K35DQET3dVYWpOaPFecqOT9dbuCfzjxoQyif1Wc574t3kOSkKevULddcR9znz1TcklCE7Ht6NIxjvTqLA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.0.tgz", + "integrity": "sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.0.tgz", + "integrity": "sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.0.tgz", + "integrity": "sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.0.tgz", + "integrity": "sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.0.tgz", + "integrity": "sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.0.tgz", + "integrity": "sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.0.tgz", + "integrity": "sha512-+rgpsNRKwo8A53elqbbHXdOMtY/tAtTzManTWShB5Kk54N8Q9mzNWV7tV+IbGueCbcj826MfWGU3mprWtuf1TA==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.0.tgz", + "integrity": "sha512-lPrxve92zEHdgeff3aiu4gDOIt4u7sJYha6wbdEZDCDUhtjTsOMiaJzG5lMY4GkWH8p0fMmO2Ppq5G5XXG+DQw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@pdf-lib/standard-fonts": { + "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" + } + }, + "node_modules/@pdf-lib/upng": { + "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" + } + }, + "node_modules/@pdfme/common": { + "version": "5.2.11", + "resolved": "https://registry.npmjs.org/@pdfme/common/-/common-5.2.11.tgz", + "integrity": "sha512-XfVn3UH0LRRzUu9NDJ0rUzxv5Nib+vyTEWiTv3KNUuO/X2553yIpzAAlrn46V+0QhW+491G+zgbr6ark0cJe4w==", + "license": "MIT", + "dependencies": { + "@pdfme/pdf-lib": "^1.18.3", + "acorn": "^8.14.0", + "buffer": "^6.0.3", + "zod": "^3.20.2" + }, + "peerDependencies": { + "antd": "^5.11.2", + "form-render": "^2.2.20" + } + }, + "node_modules/@pdfme/generator": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@pdfme/generator/-/generator-5.2.3.tgz", + "integrity": "sha512-96LxS2C3PoInHQgh5pS8Se09gvmDV1YAbyr3qotKeCdbDdbtSfbhs9NSk7h6pEIQll5z6D4k/07l3hDqxS9aFw==", + "dependencies": { + "@pdfme/pdf-lib": "^1.18.3", + "atob": "^2.1.2", + "fontkit": "^2.0.2" + }, + "peerDependencies": { + "@pdfme/common": "latest", + "@pdfme/schemas": "latest" + } + }, + "node_modules/@pdfme/pdf-lib": { + "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", + "color": "^4.2.3", + "node-html-better-parser": "^1.4.0", + "pako": "^1.0.11" + } + }, + "node_modules/@pdfme/schemas": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/@pdfme/schemas/-/schemas-5.1.6.tgz", + "integrity": "sha512-QAsWZEfe8tB3xmaj35xsGf5kSjFzMJc4F90kBbudEq8/Pkcx+0yznD7+zQK0OEj7uLD3frmXyR1OVX6dBWHBpQ==", + "license": "MIT", + "dependencies": { + "@pdfme/pdf-lib": "^1.18.3", + "air-datepicker": "^3.5.3", + "bwip-js": "^4.1.1", + "date-fns": "^4.1.0", + "fast-xml-parser": "^4.3.2", + "fontkit": "^2.0.2" + }, + "peerDependencies": { + "@pdfme/common": "latest" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@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/@rc-component/async-validator": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@rc-component/async-validator/-/async-validator-5.0.4.tgz", + "integrity": "sha512-qgGdcVIF604M9EqjNF0hbUTz42bz/RDtxWdWuU5EQe3hi7M8ob54B6B35rOsvX5eSvIHIzT9iH1R3n+hk3CGfg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.24.4" + }, + "engines": { + "node": ">=14.x" + } + }, + "node_modules/@rc-component/color-picker": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@rc-component/color-picker/-/color-picker-2.0.1.tgz", + "integrity": "sha512-WcZYwAThV/b2GISQ8F+7650r5ZZJ043E57aVBFkQ+kSY4C6wdofXgB0hBx+GPGpIU0Z81eETNoDUJMr7oy/P8Q==", + "license": "MIT", + "peer": true, + "dependencies": { + "@ant-design/fast-color": "^2.0.6", + "@babel/runtime": "^7.23.6", + "classnames": "^2.2.6", + "rc-util": "^5.38.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@rc-component/context": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@rc-component/context/-/context-1.4.0.tgz", + "integrity": "sha512-kFcNxg9oLRMoL3qki0OMxK+7g5mypjgaaJp/pkOis/6rVxma9nJBF/8kCIuTYHUQNr0ii7MxqE33wirPZLJQ2w==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.10.1", + "rc-util": "^5.27.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@rc-component/mini-decimal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rc-component/mini-decimal/-/mini-decimal-1.1.0.tgz", + "integrity": "sha512-jS4E7T9Li2GuYwI6PyiVXmxTiM6b07rlD9Ge8uGZSCz3WlzcG5ZK7g5bbuKNeZ9pgUuPK/5guV781ujdVpm4HQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.18.0" + }, + "engines": { + "node": ">=8.x" + } + }, + "node_modules/@rc-component/mutate-observer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rc-component/mutate-observer/-/mutate-observer-1.1.0.tgz", + "integrity": "sha512-QjrOsDXQusNwGZPf4/qRQasg7UFEj06XiCJ8iuiq/Io7CrHrgVi6Uuetw60WAMG1799v+aM8kyc+1L/GBbHSlw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.18.0", + "classnames": "^2.3.2", + "rc-util": "^5.24.4" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@rc-component/portal": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@rc-component/portal/-/portal-1.1.2.tgz", + "integrity": "sha512-6f813C0IsasTZms08kfA8kPAGxbbkYToa8ALaiDIGGECU4i9hj8Plgbx0sNJDrey3EtHO30hmdaxtT0138xZcg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.18.0", + "classnames": "^2.3.2", + "rc-util": "^5.24.4" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@rc-component/qrcode": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rc-component/qrcode/-/qrcode-1.0.0.tgz", + "integrity": "sha512-L+rZ4HXP2sJ1gHMGHjsg9jlYBX/SLN2D6OxP9Zn3qgtpMWtO2vUfxVFwiogHpAIqs54FnALxraUy/BCO1yRIgg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.24.7", + "classnames": "^2.3.2", + "rc-util": "^5.38.0" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@rc-component/tour": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@rc-component/tour/-/tour-1.15.1.tgz", + "integrity": "sha512-Tr2t7J1DKZUpfJuDZWHxyxWpfmj8EZrqSgyMZ+BCdvKZ6r1UDsfU46M/iWAAFBy961Ssfom2kv5f3UcjIL2CmQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.18.0", + "@rc-component/portal": "^1.0.0-9", + "@rc-component/trigger": "^2.0.0", + "classnames": "^2.3.2", + "rc-util": "^5.24.4" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@rc-component/trigger": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@rc-component/trigger/-/trigger-2.2.6.tgz", + "integrity": "sha512-/9zuTnWwhQ3S3WT1T8BubuFTT46kvnXgaERR9f4BTKyn61/wpf/BvbImzYBubzJibU707FxwbKszLlHjcLiv1Q==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.23.2", + "@rc-component/portal": "^1.1.0", + "classnames": "^2.3.2", + "rc-motion": "^2.0.0", + "rc-resize-observer": "^1.3.1", + "rc-util": "^5.44.0" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "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": { + "@swc/helpers": "^0.5.0" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" + } + }, + "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.5", + "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.7.5.tgz", + "integrity": "sha512-Tqrwz7pIlsSDITzxoLS3n/v/YCUHQdOIKtOJf4yL6kYVSDTSmVK1LI1Q3M/uu2Sx4X3pIWF3xLUhlsA6SPNTNg==", + "dependencies": { + "@react-spring/shared": "~9.7.5", + "@react-spring/types": "~9.7.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/core": { + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.7.5.tgz", + "integrity": "sha512-rmEqcxRcu7dWh7MnCcMXLvrf6/SDlSokLaLTxiPlAYi11nN3B5oiCUAblO72o+9z/87j2uzxa2Inm8UbLjXA+w==", + "dependencies": { + "@react-spring/animated": "~9.7.5", + "@react-spring/shared": "~9.7.5", + "@react-spring/types": "~9.7.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-spring/donate" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/rafz": { + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-9.7.5.tgz", + "integrity": "sha512-5ZenDQMC48wjUzPAm1EtwQ5Ot3bLIAwwqP2w2owG5KoNdNHpEJV263nGhCeKKmuA3vG2zLLOdu3or6kuDjA6Aw==" + }, + "node_modules/@react-spring/shared": { + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.7.5.tgz", + "integrity": "sha512-wdtoJrhUeeyD/PP/zo+np2s1Z820Ohr/BbuVYv+3dVLW7WctoiN7std8rISoYoHpUXtbkpesSKuPIw/6U1w1Pw==", + "dependencies": { + "@react-spring/rafz": "~9.7.5", + "@react-spring/types": "~9.7.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/types": { + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.7.5.tgz", + "integrity": "sha512-HVj7LrZ4ReHWBimBvu2SKND3cDVUPWKLqRTmWe/fNY6o1owGOX0cAHbdPDTMelgBlVbrTKrre6lFkhqGZErK/g==" + }, + "node_modules/@react-spring/web": { + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-9.7.5.tgz", + "integrity": "sha512-lmvqGwpe+CSttsWNZVr+Dg62adtKhauGwLyGE/RRyZ8AAMLgb9x3NDMA5RMElXo+IMyTkPp7nxTB8ZQlmhb6JQ==", + "dependencies": { + "@react-spring/animated": "~9.7.5", + "@react-spring/core": "~9.7.5", + "@react-spring/shared": "~9.7.5", + "@react-spring/types": "~9.7.5" + }, + "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.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.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" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@restart/ui": { + "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", + "@react-aria/ssr": "^3.5.0", + "@restart/hooks": "^0.4.9", + "@types/warning": "^3.0.0", + "dequal": "^2.0.3", + "dom-helpers": "^5.2.0", + "uncontrollable": "^8.0.1", + "warning": "^4.0.3" + }, + "peerDependencies": { + "react": ">=16.14.0", + "react-dom": ">=16.14.0" + } + }, + "node_modules/@restart/ui/node_modules/uncontrollable": { + "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-inject": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@rollup/plugin-inject/-/plugin-inject-5.0.5.tgz", + "integrity": "sha512-2+DEJbNBoPROPkgTDNe8/1YXWcqxbN5DTjASVIOx8HS+pITXushyNiBV56RB08zuptzz8gT3YfkqriTBVycepg==", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-inject/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==" + }, + "node_modules/@rollup/pluginutils": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.3.tgz", + "integrity": "sha512-Pnsb6f32CD2W3uCaLZIzDmeFyQ2b8UWMFI7xtwUezpcGBDVDW6y9XgAWIlARiGAo6eNF5FK5aQTr0LFyNyqq5A==", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils/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==" + }, + "node_modules/@rollup/pluginutils/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.21.3.tgz", + "integrity": "sha512-MmKSfaB9GX+zXl6E8z4koOr/xU63AMVleLEa64v7R0QF/ZloMs5vcD1sHgM64GXXS1csaJutG+ddtzcueI/BLg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.21.3.tgz", + "integrity": "sha512-zrt8ecH07PE3sB4jPOggweBjJMzI1JG5xI2DIsUbkA+7K+Gkjys6eV7i9pOenNSDJH3eOr/jLb/PzqtmdwDq5g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.21.3.tgz", + "integrity": "sha512-L1M0vKGO5ASKntqtsFEjTq/fD91vAqnzeaF6sfNAy55aD+Hi2pBI5DKwCO+UNDQHWsDViJLqshxOahXyLSh3EA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.21.3.tgz", + "integrity": "sha512-btVgIsCjuYFKUjopPoWiDqmoUXQDiW2A4C3Mtmp5vACm7/GnyuprqIDPNczeyR5W8rTXEbkmrJux7cJmD99D2g==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.21.3.tgz", + "integrity": "sha512-zmjbSphplZlau6ZTkxd3+NMtE4UKVy7U4aVFMmHcgO5CUbw17ZP6QCgyxhzGaU/wFFdTfiojjbLG3/0p9HhAqA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.21.3.tgz", + "integrity": "sha512-nSZfcZtAnQPRZmUkUQwZq2OjQciR6tEoJaZVFvLHsj0MF6QhNMg0fQ6mUOsiCUpTqxTx0/O6gX0V/nYc7LrgPw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.21.3.tgz", + "integrity": "sha512-MnvSPGO8KJXIMGlQDYfvYS3IosFN2rKsvxRpPO2l2cum+Z3exiExLwVU+GExL96pn8IP+GdH8Tz70EpBhO0sIQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.21.3.tgz", + "integrity": "sha512-+W+p/9QNDr2vE2AXU0qIy0qQE75E8RTwTwgqS2G5CRQ11vzq0tbnfBd6brWhS9bCRjAjepJe2fvvkvS3dno+iw==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.21.3.tgz", + "integrity": "sha512-yXH6K6KfqGXaxHrtr+Uoy+JpNlUlI46BKVyonGiaD74ravdnF9BUNC+vV+SIuB96hUMGShhKV693rF9QDfO6nQ==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.21.3.tgz", + "integrity": "sha512-R8cwY9wcnApN/KDYWTH4gV/ypvy9yZUHlbJvfaiXSB48JO3KpwSpjOGqO4jnGkLDSk1hgjYkTbTt6Q7uvPf8eg==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.3.tgz", + "integrity": "sha512-kZPbX/NOPh0vhS5sI+dR8L1bU2cSO9FgxwM8r7wHzGydzfSjLRCFAT87GR5U9scj2rhzN3JPYVC7NoBbl4FZ0g==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.21.3.tgz", + "integrity": "sha512-S0Yq+xA1VEH66uiMNhijsWAafffydd2X5b77eLHfRmfLsRSpbiAWiRHV6DEpz6aOToPsgid7TI9rGd6zB1rhbg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.21.3.tgz", + "integrity": "sha512-9isNzeL34yquCPyerog+IMCNxKR8XYmGd0tHSV+OVx0TmE0aJOo9uw4fZfUuk2qxobP5sug6vNdZR6u7Mw7Q+Q==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.21.3.tgz", + "integrity": "sha512-nMIdKnfZfzn1Vsk+RuOvl43ONTZXoAPUUxgcU0tXooqg4YrAqzfKzVenqqk2g5efWh46/D28cKFrOzDSW28gTA==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "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": { + "@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/@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": { + "@shikijs/types": "1.17.6", + "oniguruma-to-js": "0.4.3" + } + }, + "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": { + "@shikijs/types": "1.17.6", + "@shikijs/vscode-textmate": "^9.2.2" + } + }, + "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": { + "@shikijs/vscode-textmate": "^9.2.2", + "@types/hast": "^3.0.4" + } + }, + "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", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sinonjs/commons": { + "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" + } + }, + "node_modules/@sinonjs/fake-timers": { + "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/@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", + "integrity": "sha512-9PYGcXrAxitycIjRmZB+Q0JaN07GZIWaTBIGQzfaZv+qr1n8X1XUEJ5rZ/vx6OVD9RRYlrNnXWExQXcmZeD/BQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", + "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-6.5.1.tgz", + "integrity": "sha512-8DPaVVE3fd5JKuIC29dqyMB54sA6mfgki2H2+swh+zNJoynC8pMPzOkidqHOSc6Wj032fhl8Z0TVn1GiPpAiJg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-dynamic-title": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-6.5.1.tgz", + "integrity": "sha512-FwOEi0Il72iAzlkaHrlemVurgSQRDFbk0OC8dSvD5fSBPHltNh7JtLsxmZUhjYBZo2PpcU/RJvvi6Q0l7O7ogw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-em-dimensions": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-6.5.1.tgz", + "integrity": "sha512-gWGsiwjb4tw+ITOJ86ndY/DZZ6cuXMNE/SjcDRg+HLuCmwpcjOktwRF9WgAiycTqJD/QXqL2f8IzE2Rzh7aVXA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-react-native-svg": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-6.5.1.tgz", + "integrity": "sha512-2jT3nTayyYP7kI6aGutkyfJ7UMGtuguD72OjeGLwVNyfPRBD8zQthlvL+fAbAKk5n9ZNcvFkp/b1lZ7VsYqVJg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-svg-component": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-6.5.1.tgz", + "integrity": "sha512-a1p6LF5Jt33O3rZoVRBqdxL350oge54iZWHNI6LJB5tQ7EelvD/Mb1mfBiZNAan0dt4i3VArkFRjA4iObuNykQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-preset": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-6.5.1.tgz", + "integrity": "sha512-6127fvO/FF2oi5EzSQOAjo1LE3OtNVh11R+/8FXa+mHx1ptAaS4cknIjnUA7e6j6fwGGJ17NzaTJFUwOV2zwCw==", + "dev": true, + "dependencies": { + "@svgr/babel-plugin-add-jsx-attribute": "^6.5.1", + "@svgr/babel-plugin-remove-jsx-attribute": "*", + "@svgr/babel-plugin-remove-jsx-empty-expression": "*", + "@svgr/babel-plugin-replace-jsx-attribute-value": "^6.5.1", + "@svgr/babel-plugin-svg-dynamic-title": "^6.5.1", + "@svgr/babel-plugin-svg-em-dimensions": "^6.5.1", + "@svgr/babel-plugin-transform-react-native-svg": "^6.5.1", + "@svgr/babel-plugin-transform-svg-component": "^6.5.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/core": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-6.5.1.tgz", + "integrity": "sha512-/xdLSWxK5QkqG524ONSjvg3V/FkNyCv538OIBdQqPNaAta3AsXj/Bd2FbvR87yMbXO2hFSWiAe/Q6IkVPDw+mw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.19.6", + "@svgr/babel-preset": "^6.5.1", + "@svgr/plugin-jsx": "^6.5.1", + "camelcase": "^6.2.0", + "cosmiconfig": "^7.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/core/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": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@svgr/hast-util-to-babel-ast": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-6.5.1.tgz", + "integrity": "sha512-1hnUxxjd83EAxbL4a0JDJoD3Dao3hmjvyvyEV8PzWmLK3B9m9NPlW7GKjFyoWE8nM7HnXzPcmmSyOW8yOddSXw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.0", + "entities": "^4.4.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/plugin-jsx": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-6.5.1.tgz", + "integrity": "sha512-+UdQxI3jgtSjCykNSlEMuy1jSRQlGC7pqBCPvkG/2dATdWo082zHTTK3uhnAju2/6XpE6B5mZ3z4Z8Ns01S8Gw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.19.6", + "@svgr/babel-preset": "^6.5.1", + "@svgr/hast-util-to-babel-ast": "^6.5.1", + "svg-parser": "^2.0.4" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "^6.0.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": "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" + }, + "engines": { + "node": ">=18" + } + }, + "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" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "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" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "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": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "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, + "peer": true + }, + "node_modules/@testing-library/jest-dom": { + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.6.3.tgz", + "integrity": "sha512-IteBhl4XqYNkM54f4ejhLRJiZNqcSCoXUOG2CPK7qbD322KjQozM4kHQOfkG2oln9b9HTYqs+Sae8vBATubxxA==", + "dev": true, + "dependencies": { + "@adobe/css-tools": "^4.4.0", + "aria-query": "^5.0.0", + "chalk": "^3.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "lodash": "^4.17.21", + "redent": "^3.0.0" + }, + "engines": { + "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": "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" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@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": { + "version": "12.8.3", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-12.8.3.tgz", + "integrity": "sha512-IR0iWbFkgd56Bu5ZI/ej8yQwrkCv8Qydx6RzwbKz9faXazR/+5tvYKsZQgyXJiwgpcva127YO6JcWy7YlCfofQ==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + }, + "peerDependencies": { + "@testing-library/dom": ">=7.21.4" + } + }, + "node_modules/@tootallnate/once": { + "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/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true, + "peer": true + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.1.tgz", + "integrity": "sha512-MitHFXnhtgwsGZWtT68URpOvLN4EREih1u3QtQiN4VdAxWKRVvGCSvw/Qth0M0Qq3pJpnGOu5JaM/ydK7OGbqg==", + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "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/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/d3-color": "*" + } + }, + "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/d3-time": "*" + } + }, + "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/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/estree": { + "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", + "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==", + "dev": true + }, + "node_modules/@types/hoist-non-react-statics": { + "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/inquirer": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@types/inquirer/-/inquirer-9.0.7.tgz", + "integrity": "sha512-Q0zyBupO6NxGRZut/JdmqYKOnN95Eg5V8Csg3PGKkP+FnvsUZx1jAyK7fztIszxxMuoBA6E3KXWvdZVXIpx60g==", + "dev": true, + "dependencies": { + "@types/through": "*", + "rxjs": "^7.2.0" + } + }, + "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==", + "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": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "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": "*" + } + }, + "node_modules/@types/jest": { + "version": "26.0.24", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.24.tgz", + "integrity": "sha512-E/X5Vib8BWqZNRlDxj9vYXhsDwPYbPINqKF9BsnSoon4RQ0D9moEuLD8txgyypFLH7J4+Lho9Nr/c8H0Fi+17w==", + "dev": true, + "dependencies": { + "jest-diff": "^26.0.0", + "pretty-format": "^26.0.0" + } + }, + "node_modules/@types/js-cookie": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/js-cookie/-/js-cookie-3.0.6.tgz", + "integrity": "sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", + "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "node_modules/@types/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/mute-stream": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@types/mute-stream/-/mute-stream-0.0.4.tgz", + "integrity": "sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "22.9.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.0.tgz", + "integrity": "sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==", + "dependencies": { + "undici-types": "~6.19.8" + } + }, + "node_modules/@types/node-fetch": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==", + "dev": true, + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.0" + } + }, + "node_modules/@types/node-fetch/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" + }, + "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==", + "dev": true + }, + "node_modules/@types/prop-types": { + "version": "15.7.13", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", + "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==" + }, + "node_modules/@types/react": { + "version": "18.3.12", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz", + "integrity": "sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==", + "dependencies": { + "@types/prop-types": "*", + "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.37", + "resolved": "https://registry.npmjs.org/@types/react-bootstrap/-/react-bootstrap-0.32.37.tgz", + "integrity": "sha512-CVHj++uxsj1pRnM3RQ/NAXcWj+JwJZ3MqQ28sS1OQUD1sI2gRlbeAjRT+ak2nuwL+CY+gtnIsMaIDq0RNfN0PA==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-chartjs-2": { + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/@types/react-chartjs-2/-/react-chartjs-2-2.5.7.tgz", + "integrity": "sha512-waqYqiNULIVUqaKO7MGUpFmWrVtH7gVPOzqwV4y4zgUyu/JiDwC005PpveO442HKnby9kLgp3t1SB2sld+ACLw==", + "deprecated": "This is a stub types definition for react-chartjs-2 (https://github.com/gor181/react-chartjs-2). react-chartjs-2 provides its own type definitions, so you don't need @types/react-chartjs-2 installed!", + "dev": true, + "license": "MIT", + "dependencies": { + "react-chartjs-2": "*" + } + }, + "node_modules/@types/react-datepicker": { + "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": { + "react-datepicker": "*" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-google-recaptcha": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@types/react-google-recaptcha/-/react-google-recaptcha-2.1.9.tgz", + "integrity": "sha512-nT31LrBDuoSZJN4QuwtQSF3O89FVHC4jLhM+NtKEmVF5R1e8OY0Jo4//x2Yapn2aNHguwgX5doAq8Zo+Ehd0ug==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "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": { + "@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-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": { + "@babel/runtime": "^7.9.2" + } + }, + "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.11", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.11.tgz", + "integrity": "sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/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": { + "htmlparser2": "^8.0.0" + } + }, + "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": { + "@types/node": "*" + } + }, + "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/wrap-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz", + "integrity": "sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==", + "license": "MIT" + }, + "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": { + "@types/yargs-parser": "*" + } + }, + "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/@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": { + "@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": ">=14.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui-org" + "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@emotion/react": "^11.9.0", - "@emotion/styled": "^11.8.1", - "@mui/material": "^5.15.14", - "date-fns": "^2.25.0 || ^3.2.0", - "date-fns-jalali": "^2.13.0-0 || ^3.2.0-0", - "dayjs": "^1.10.7", - "luxon": "^3.0.2", - "moment": "^2.29.4", - "moment-hijri": "^2.1.2", - "moment-jalaali": "^0.7.4 || ^0.8.0 || ^0.9.0 || ^0.10.0", - "react": "^17.0.0 || ^18.0.0", - "react-dom": "^17.0.0 || ^18.0.0" + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0" }, "peerDependenciesMeta": { - "@emotion/react": { - "optional": true - }, - "@emotion/styled": { - "optional": true - }, - "date-fns": { - "optional": true - }, - "date-fns-jalali": { - "optional": true - }, - "dayjs": { - "optional": true - }, - "luxon": { - "optional": true - }, - "moment": { - "optional": true - }, - "moment-hijri": { - "optional": true - }, - "moment-jalaali": { + "typescript": { "optional": true } } }, - "node_modules/@mui/x-internals": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-7.16.0.tgz", - "integrity": "sha512-ijer5XYmWlJqWaTmF6TGH1odG7EAupv8iDWYmDm2yVR9IQ+L2nQSuhiFClI+wmGx40KS2VKOlzDMPpF0t7/HCg==", + "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": { - "@babel/runtime": "^7.25.6", - "@mui/utils": "^5.16.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.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui-org" + "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "react": "^17.0.0 || ^18.0.0" + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "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==", + "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": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "@typescript-eslint/types": "8.5.0", + "@typescript-eslint/visitor-keys": "8.5.0" }, "engines": { - "node": ">= 8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "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": ">= 8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "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": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" + "@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": ">= 8" + "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/@pdf-lib/standard-fonts": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@pdf-lib/standard-fonts/-/standard-fonts-1.0.0.tgz", - "integrity": "sha512-hU30BK9IUN/su0Mn9VdlVKsWBS6GyhVfqjwl1FjZN4TxP6cCw0jP2w7V3Hf5uX7M0AZJ16vey9yE0ny7Sa59ZA==", + "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": { - "pako": "^1.0.6" + "@typescript-eslint/types": "8.5.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@pdf-lib/upng": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@pdf-lib/upng/-/upng-1.0.1.tgz", - "integrity": "sha512-dQK2FUMQtowVP00mtIksrlZhdFXQZPC+taih1q4CvPZ5vqdxR/LKBaFg0oAfzd1GlHZXXSPdQfzQnt+ViGvEIQ==", + "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": { - "pako": "^1.0.10" + "balanced-match": "^1.0.0" } }, - "node_modules/@pdfme/common": { - "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, + "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": { - "buffer": "^6.0.3", - "fontkit": "^2.0.2", - "zod": "^3.20.2" + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=14" - } - }, - "node_modules/@pdfme/generator": { - "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/pdf-lib": "^1.18.3", - "atob": "^2.1.2", - "fontkit": "^2.0.2" + "node": ">=16 || 14 >=14.17" }, - "peerDependencies": { - "@pdfme/common": "latest", - "@pdfme/schemas": "latest" - } - }, - "node_modules/@pdfme/pdf-lib": { - "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", - "color": "^4.2.3", - "node-html-better-parser": "^1.4.0", - "pako": "^1.0.11" + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "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, + "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": { - "@pdfme/pdf-lib": "^1.18.3", - "bwip-js": "^4.1.1", - "fast-xml-parser": "^4.3.2", - "fontkit": "^2.0.2" + "@typescript-eslint/types": "8.11.0", + "@typescript-eslint/visitor-keys": "8.11.0" }, - "peerDependencies": { - "@pdfme/common": "latest" + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@pkgr/core": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", - "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "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": { + "@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": "^12.20.0 || ^14.18.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/unts" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "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==", + "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": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/popperjs" + "url": "https://opencollective.com/typescript-eslint" } }, - "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==", + "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": { - "@swc/helpers": "^0.5.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" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "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==", + "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": { - "tslib": "^2.4.0" + "balanced-match": "^1.0.0" } }, - "node_modules/@react-spring/animated": { - "version": "9.7.4", - "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.7.4.tgz", - "integrity": "sha512-7As+8Pty2QlemJ9O5ecsuPKjmO0NKvmVkRR1n6mEotFgWar8FKuQt2xgxz3RTgxcccghpx1YdS1FCdElQNexmQ==", + "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": { - "@react-spring/shared": "~9.7.4", - "@react-spring/types": "~9.7.4" + "brace-expansion": "^2.0.1" }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@react-spring/core": { - "version": "9.7.4", - "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.7.4.tgz", - "integrity": "sha512-GzjA44niEJBFUe9jN3zubRDDDP2E4tBlhNlSIkTChiNf9p4ZQlgXBg50qbXfSXHQPHak/ExYxwhipKVsQ/sUTw==", + "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": { - "@react-spring/animated": "~9.7.4", - "@react-spring/shared": "~9.7.4", - "@react-spring/types": "~9.7.4" + "@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": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/react-spring/donate" + "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + "eslint": "^8.57.0 || ^9.0.0" } }, - "node_modules/@react-spring/rafz": { - "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.4", - "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.7.4.tgz", - "integrity": "sha512-bEPI7cQp94dOtCFSEYpxvLxj0+xQfB5r9Ru1h8OMycsIq7zFZon1G0sHrBLaLQIWeMCllc4tVDYRTLIRv70C8w==", + "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": { - "@react-spring/rafz": "~9.7.4", - "@react-spring/types": "~9.7.4" + "@typescript-eslint/types": "8.11.0", + "eslint-visitor-keys": "^3.4.3" }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@react-spring/types": { - "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/@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/@react-spring/web": { - "version": "9.7.4", - "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-9.7.4.tgz", - "integrity": "sha512-UMvCZp7I5HCVIleSa4BwbNxynqvj+mJjG2m20VO2yPoi2pnCYANy58flvz9v/YcXTAvsmL655FV3pm5fbr6akA==", + "node_modules/@vitejs/plugin-react": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.3.tgz", + "integrity": "sha512-NooDe9GpHGqNns1i8XDERg0Vsg5SSYRhRxxyTGogUdkdNt47jal+fbuYi+Yfq6pzRCKXyoPcWisfxE6RIM3GKA==", "dependencies": { - "@react-spring/animated": "~9.7.4", - "@react-spring/core": "~9.7.4", - "@react-spring/shared": "~9.7.4", - "@react-spring/types": "~9.7.4" + "@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": "^14.18.0 || >=16.0.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + "vite": "^4.2.0 || ^5.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==", + "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": ">=0.10.0" + } + }, + "node_modules/@vitest/coverage-istanbul": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@vitest/coverage-istanbul/-/coverage-istanbul-2.1.5.tgz", + "integrity": "sha512-jJsS5jeHncmSvzMNE03F1pk8F9etmjzGmGyQnGMkdHdVek/bxK/3vo8Qr3e9XmVuDM3UZKOy1ObeQHgC2OxvHg==", + "dev": true, "dependencies": { - "immer": "^10.0.3", - "redux": "^5.0.1", - "redux-thunk": "^3.1.0", - "reselect": "^5.1.0" + "@istanbuljs/schema": "^0.1.3", + "debug": "^4.3.7", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-instrument": "^6.0.3", + "istanbul-lib-report": "^3.0.1", + "istanbul-lib-source-maps": "^5.0.6", + "istanbul-reports": "^3.1.7", + "magicast": "^0.3.5", + "test-exclude": "^7.0.1", + "tinyrainbow": "^1.2.0" }, - "peerDependencies": { - "react": "^16.9.0 || ^17.0.0 || ^18", - "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" + "funding": { + "url": "https://opencollective.com/vitest" }, - "peerDependenciesMeta": { - "react": { - "optional": true - }, - "react-redux": { - "optional": true - } + "peerDependencies": { + "vitest": "2.1.5" } }, - "node_modules/@remix-run/router": { - "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/@vitest/coverage-istanbul/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" } }, - "node_modules/@restart/hooks": { - "version": "0.4.16", - "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.16.tgz", - "integrity": "sha512-f7aCv7c+nU/3mF7NWLtVVr0Ra80RqsO89hO72r+Y/nvQr5+q0UFGkocElTH6MJApvReVh6JHUFYn2cw1WdHF3w==", + "node_modules/@vitest/coverage-istanbul/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, "dependencies": { - "dequal": "^2.0.3" + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" }, - "peerDependencies": { - "react": ">=16.8.0" + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@restart/ui": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.8.0.tgz", - "integrity": "sha512-xJEOXUOTmT4FngTmhdjKFRrVVF0hwCLNPdatLCHkyS4dkiSK12cEu1Y0fjxktjJrdst9jJIc5J6ihMJCoWEN/g==", + "node_modules/@vitest/coverage-istanbul/node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, "dependencies": { - "@babel/runtime": "^7.21.0", - "@popperjs/core": "^2.11.6", - "@react-aria/ssr": "^3.5.0", - "@restart/hooks": "^0.4.9", - "@types/warning": "^3.0.0", - "dequal": "^2.0.3", - "dom-helpers": "^5.2.0", - "uncontrollable": "^8.0.1", - "warning": "^4.0.3" + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" }, - "peerDependencies": { - "react": ">=16.14.0", - "react-dom": ">=16.14.0" + "engines": { + "node": ">=10" } }, - "node_modules/@restart/ui/node_modules/uncontrollable": { - "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/@vitest/coverage-istanbul/node_modules/istanbul-lib-source-maps": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.23", + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0" + }, + "engines": { + "node": ">=10" } }, - "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/@vitest/coverage-istanbul/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } }, - "node_modules/@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==", + "node_modules/@vitest/coverage-istanbul/node_modules/test-exclude": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz", + "integrity": "sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==", + "dev": true, "dependencies": { - "@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" + "@istanbuljs/schema": "^0.1.2", + "glob": "^10.4.1", + "minimatch": "^9.0.4" + }, + "engines": { + "node": ">=18" } }, - "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==", + "node_modules/@vitest/expect": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.5.tgz", + "integrity": "sha512-nZSBTW1XIdpZvEJyoP/Sy8fUg0b8od7ZpGDkTUcfJ7wz/VoZAFzFfLyxVxGFhUjJzhYqSbIpfMtl/+k/dpWa3Q==", + "dev": true, + "license": "MIT", "dependencies": { - "@shikijs/types": "1.17.6", - "oniguruma-to-js": "0.4.3" + "@vitest/spy": "2.1.5", + "@vitest/utils": "2.1.5", + "chai": "^5.1.2", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "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==", + "node_modules/@vitest/mocker": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.5.tgz", + "integrity": "sha512-XYW6l3UuBmitWqSUXTNXcVBUCRytDogBsWuNXQijc00dtnU/9OqpXWp4OJroVrad/gLIomAq9aW8yWDBtMthhQ==", + "dev": true, + "license": "MIT", "dependencies": { - "@shikijs/types": "1.17.6", - "@shikijs/vscode-textmate": "^9.2.2" + "@vitest/spy": "2.1.5", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.12" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } } }, - "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==", + "node_modules/@vitest/pretty-format": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.8.tgz", + "integrity": "sha512-9HiSZ9zpqNLKlbIDRWOnAWqgcA7xu+8YxXSekhr0Ykab7PAYFkhkwoqVArPOtJhPmYeE2YHgKZlj3CP36z2AJQ==", + "dev": true, + "license": "MIT", "dependencies": { - "@shikijs/vscode-textmate": "^9.2.2", - "@types/hast": "^3.0.4" + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "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", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "node_modules/@vitest/runner": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.5.tgz", + "integrity": "sha512-pKHKy3uaUdh7X6p1pxOkgkVAFW7r2I818vHDthYLvUyjRfkKOU6P45PztOch4DZarWQne+VOaIMwA/erSSpB9g==", "dev": true, - "engines": { - "node": ">=6" + "license": "MIT", + "dependencies": { + "@vitest/utils": "2.1.5", + "pathe": "^1.1.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/@sinonjs/commons": { - "version": "1.8.6", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", - "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "node_modules/@vitest/snapshot": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.5.tgz", + "integrity": "sha512-zmYw47mhfdfnYbuhkQvkkzYroXUumrwWDGlMjpdUr4jBd3HZiV2w7CQHj+z7AAS4VOtWxI4Zt4bWt4/sKcoIjg==", "dev": true, + "license": "MIT", "dependencies": { - "type-detect": "4.0.8" + "@vitest/pretty-format": "2.1.5", + "magic-string": "^0.30.12", + "pathe": "^1.1.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/@sinonjs/fake-timers": { - "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==", + "node_modules/@vitest/snapshot/node_modules/@vitest/pretty-format": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.5.tgz", + "integrity": "sha512-4ZOwtk2bqG5Y6xRGHcveZVr+6txkH7M2e+nPFd6guSoN638v/1XQ0K06eOpi0ptVU/2tW/pIU4IoPotY/GZ9fw==", "dev": true, + "license": "MIT", "dependencies": { - "@sinonjs/commons": "^1.7.0" + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "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", - "integrity": "sha512-9PYGcXrAxitycIjRmZB+Q0JaN07GZIWaTBIGQzfaZv+qr1n8X1XUEJ5rZ/vx6OVD9RRYlrNnXWExQXcmZeD/BQ==", + "node_modules/@vitest/spy": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.5.tgz", + "integrity": "sha512-aWZF3P0r3w6DiYTVskOYuhBc7EMc3jvn1TkBg8ttylFFRqNN2XGD7V5a4aQdk6QiUzZQ4klNBSpCLJgWNdIiNw==", "dev": true, - "engines": { - "node": ">=10" + "license": "MIT", + "dependencies": { + "tinyspy": "^3.0.2" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "url": "https://opencollective.com/vitest" } }, - "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", - "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", + "node_modules/@vitest/utils": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.5.tgz", + "integrity": "sha512-yfj6Yrp0Vesw2cwJbP+cl04OC+IHFsuQsrsJBL9pyGeQXE56v1UAOQco+SR55Vf1nQzfV0QJg1Qum7AaWUwwYg==", "dev": true, - "engines": { - "node": ">=14" + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "2.1.5", + "loupe": "^3.1.2", + "tinyrainbow": "^1.2.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "url": "https://opencollective.com/vitest" } }, - "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", - "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", + "node_modules/@vitest/utils/node_modules/@vitest/pretty-format": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.5.tgz", + "integrity": "sha512-4ZOwtk2bqG5Y6xRGHcveZVr+6txkH7M2e+nPFd6guSoN638v/1XQ0K06eOpi0ptVU/2tW/pIU4IoPotY/GZ9fw==", "dev": true, - "engines": { - "node": ">=14" + "license": "MIT", + "dependencies": { + "tinyrainbow": "^1.2.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "url": "https://opencollective.com/vitest" } }, - "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-6.5.1.tgz", - "integrity": "sha512-8DPaVVE3fd5JKuIC29dqyMB54sA6mfgki2H2+swh+zNJoynC8pMPzOkidqHOSc6Wj032fhl8Z0TVn1GiPpAiJg==", - "dev": true, + "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": { + "tslib": "^2.3.0" + }, "engines": { - "node": ">=10" + "node": ">=8" + } + }, + "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": { + "tslib": "^2.3.0" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" + "engines": { + "node": ">=8" + } + }, + "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": { + "tslib": "^2.3.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=8" } }, - "node_modules/@svgr/babel-plugin-svg-dynamic-title": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-6.5.1.tgz", - "integrity": "sha512-FwOEi0Il72iAzlkaHrlemVurgSQRDFbk0OC8dSvD5fSBPHltNh7JtLsxmZUhjYBZo2PpcU/RJvvi6Q0l7O7ogw==", - "dev": true, + "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": { + "tslib": "^2.3.0" + }, "engines": { - "node": ">=10" + "node": ">=8" + } + }, + "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/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" + "engines": { + "node": ">=0.4.0" + } + }, + "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": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + } + }, + "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": ">=0.4.0" + } + }, + "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", "peerDependencies": { - "@babel/core": "^7.0.0-0" + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/@svgr/babel-plugin-svg-em-dimensions": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-6.5.1.tgz", - "integrity": "sha512-gWGsiwjb4tw+ITOJ86ndY/DZZ6cuXMNE/SjcDRg+HLuCmwpcjOktwRF9WgAiycTqJD/QXqL2f8IzE2Rzh7aVXA==", + "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": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=0.4.0" } }, - "node_modules/@svgr/babel-plugin-transform-react-native-svg": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-6.5.1.tgz", - "integrity": "sha512-2jT3nTayyYP7kI6aGutkyfJ7UMGtuguD72OjeGLwVNyfPRBD8zQthlvL+fAbAKk5n9ZNcvFkp/b1lZ7VsYqVJg==", + "node_modules/add-dom-event-listener": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/add-dom-event-listener/-/add-dom-event-listener-1.1.0.tgz", + "integrity": "sha512-WCxx1ixHT0GQU9hb0KI/mhgRQhnU+U3GvwY6ZvVjYq8rsihIGoaIOUbY0yMPBxLH5MDtr0kz3fisWGNcbWW7Jw==", + "license": "MIT", + "peer": true, + "dependencies": { + "object-assign": "4.x" + } + }, + "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": { + "debug": "4" + }, "engines": { - "node": ">=10" + "node": ">= 6.0.0" + } + }, + "node_modules/ahooks": { + "version": "3.8.4", + "resolved": "https://registry.npmjs.org/ahooks/-/ahooks-3.8.4.tgz", + "integrity": "sha512-39wDEw2ZHvypaT14EpMMk4AzosHWt0z9bulY0BeDsvc9PqJEV+Kjh/4TZfftSsotBMq52iYIOFPd3PR56e0ZJg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.21.0", + "dayjs": "^1.9.1", + "intersection-observer": "^0.12.0", + "js-cookie": "^3.0.5", + "lodash": "^4.17.21", + "react-fast-compare": "^3.2.2", + "resize-observer-polyfill": "^1.5.1", + "screenfull": "^5.0.0", + "tslib": "^2.4.1" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" + "engines": { + "node": ">=8.0.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, - "node_modules/@svgr/babel-plugin-transform-svg-component": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-6.5.1.tgz", - "integrity": "sha512-a1p6LF5Jt33O3rZoVRBqdxL350oge54iZWHNI6LJB5tQ7EelvD/Mb1mfBiZNAan0dt4i3VArkFRjA4iObuNykQ==", + "node_modules/air-datepicker": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/air-datepicker/-/air-datepicker-3.5.3.tgz", + "integrity": "sha512-Elf9gLhv/jidN1+TfeRJYMQRUfYx5apXw2dY5DuAMPRnNtQ4Iw9fTTJK772osmXSUB9xQ2Y8Q1Pt6pgBOQLPQw==", + "license": "MIT" + }, + "node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dev": true, - "engines": { - "node": ">=12" + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" }, "funding": { "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@svgr/babel-preset": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-6.5.1.tgz", - "integrity": "sha512-6127fvO/FF2oi5EzSQOAjo1LE3OtNVh11R+/8FXa+mHx1ptAaS4cknIjnUA7e6j6fwGGJ17NzaTJFUwOV2zwCw==", + "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": { - "@svgr/babel-plugin-add-jsx-attribute": "^6.5.1", - "@svgr/babel-plugin-remove-jsx-attribute": "*", - "@svgr/babel-plugin-remove-jsx-empty-expression": "*", - "@svgr/babel-plugin-replace-jsx-attribute-value": "^6.5.1", - "@svgr/babel-plugin-svg-dynamic-title": "^6.5.1", - "@svgr/babel-plugin-svg-em-dimensions": "^6.5.1", - "@svgr/babel-plugin-transform-react-native-svg": "^6.5.1", - "@svgr/babel-plugin-transform-svg-component": "^6.5.1" + "string-width": "^4.1.0" + } + }, + "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": ">=10" + "node": ">=8" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@svgr/core": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/core/-/core-6.5.1.tgz", - "integrity": "sha512-/xdLSWxK5QkqG524ONSjvg3V/FkNyCv538OIBdQqPNaAta3AsXj/Bd2FbvR87yMbXO2hFSWiAe/Q6IkVPDw+mw==", - "dev": true, + "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": { - "@babel/core": "^7.19.6", - "@svgr/babel-preset": "^6.5.1", - "@svgr/plugin-jsx": "^6.5.1", - "camelcase": "^6.2.0", - "cosmiconfig": "^7.0.1" + "ansi-wrap": "0.1.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" + "node": ">=0.10.0" } }, - "node_modules/@svgr/core/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, + "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": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, - "node_modules/@svgr/hast-util-to-babel-ast": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-6.5.1.tgz", - "integrity": "sha512-1hnUxxjd83EAxbL4a0JDJoD3Dao3hmjvyvyEV8PzWmLK3B9m9NPlW7GKjFyoWE8nM7HnXzPcmmSyOW8yOddSXw==", - "dev": true, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dependencies": { - "@babel/types": "^7.20.0", - "entities": "^4.4.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=8" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@svgr/plugin-jsx": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-6.5.1.tgz", - "integrity": "sha512-+UdQxI3jgtSjCykNSlEMuy1jSRQlGC7pqBCPvkG/2dATdWo082zHTTK3uhnAju2/6XpE6B5mZ3z4Z8Ns01S8Gw==", - "dev": true, - "dependencies": { - "@babel/core": "^7.19.6", - "@svgr/babel-preset": "^6.5.1", - "@svgr/hast-util-to-babel-ast": "^6.5.1", - "svg-parser": "^2.0.4" - }, + "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": ">=10" + "node": ">=0.10.0" + } + }, + "node_modules/antd": { + "version": "5.22.6", + "resolved": "https://registry.npmjs.org/antd/-/antd-5.22.6.tgz", + "integrity": "sha512-ZYURSV3FR8qQgbfpa554thlO07L6PeHwhAM0wmxnobOBogND/HqSnTU+UZTqT2b2y9MxSfAIu5Xn1uEM9UpceQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@ant-design/colors": "^7.1.0", + "@ant-design/cssinjs": "^1.21.1", + "@ant-design/cssinjs-utils": "^1.1.3", + "@ant-design/icons": "^5.5.2", + "@ant-design/react-slick": "~1.1.2", + "@babel/runtime": "^7.25.7", + "@ctrl/tinycolor": "^3.6.1", + "@rc-component/color-picker": "~2.0.1", + "@rc-component/mutate-observer": "^1.1.0", + "@rc-component/qrcode": "~1.0.0", + "@rc-component/tour": "~1.15.1", + "@rc-component/trigger": "^2.2.6", + "classnames": "^2.5.1", + "copy-to-clipboard": "^3.3.3", + "dayjs": "^1.11.11", + "rc-cascader": "~3.30.0", + "rc-checkbox": "~3.3.0", + "rc-collapse": "~3.9.0", + "rc-dialog": "~9.6.0", + "rc-drawer": "~7.2.0", + "rc-dropdown": "~4.2.1", + "rc-field-form": "~2.7.0", + "rc-image": "~7.11.0", + "rc-input": "~1.6.4", + "rc-input-number": "~9.3.0", + "rc-mentions": "~2.17.0", + "rc-menu": "~9.16.0", + "rc-motion": "^2.9.5", + "rc-notification": "~5.6.2", + "rc-pagination": "~5.0.0", + "rc-picker": "~4.8.3", + "rc-progress": "~4.0.0", + "rc-rate": "~2.13.0", + "rc-resize-observer": "^1.4.3", + "rc-segmented": "~2.5.0", + "rc-select": "~14.16.4", + "rc-slider": "~11.1.7", + "rc-steps": "~6.0.1", + "rc-switch": "~4.1.0", + "rc-table": "~7.49.0", + "rc-tabs": "~15.4.0", + "rc-textarea": "~1.8.2", + "rc-tooltip": "~6.2.1", + "rc-tree": "~5.10.1", + "rc-tree-select": "~5.24.5", + "rc-upload": "~4.8.1", + "rc-util": "^5.44.2", + "scroll-into-view-if-needed": "^3.1.0", + "throttle-debounce": "^5.0.2" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" + "type": "opencollective", + "url": "https://opencollective.com/ant-design" }, "peerDependencies": { - "@svgr/core": "^6.0.0" + "react": ">=16.9.0", + "react-dom": ">=16.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/antd/node_modules/throttle-debounce": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-5.0.2.tgz", + "integrity": "sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12.22" } }, - "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==", + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, "dependencies": { - "defer-to-connect": "^1.0.1" + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" }, "engines": { - "node": ">=6" + "node": ">= 8" } }, - "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==", + "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/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, - "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" - }, - "engines": { - "node": ">=18" + "dequal": "^2.0.3" } }, - "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/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, - "peer": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "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==", + "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, - "peer": true, "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" + "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": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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==", + "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, - "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "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, - "peer": true - }, - "node_modules/@testing-library/jest-dom": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.5.0.tgz", - "integrity": "sha512-xGGHpBXYSHUUr6XsKBfs85TWlYKpTc37cSBBVrXcib2MkHLboWlkClhWF37JKlDb9KEq3dHs+f2xR7XJEWGBxA==", + "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": { - "@adobe/css-tools": "^4.4.0", - "aria-query": "^5.0.0", - "chalk": "^3.0.0", - "css.escape": "^1.5.1", - "dom-accessibility-api": "^0.6.3", - "lodash": "^4.17.21", - "redent": "^3.0.0" + "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": ">=14", - "npm": ">=6", - "yarn": ">=1" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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": "16.0.1", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.0.1.tgz", - "integrity": "sha512-dSmwJVtJXmku+iocRhWOUFbrERC76TX2Mnf0ATODz8brzAZrMBbzLwQixlBSanZxR6LddK3eiwpSFZgDET1URg==", + "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": { - "@babel/runtime": "^7.12.5" + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" }, "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@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" + "node": ">= 0.4" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@testing-library/user-event": { - "version": "12.8.3", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-12.8.3.tgz", - "integrity": "sha512-IR0iWbFkgd56Bu5ZI/ej8yQwrkCv8Qydx6RzwbKz9faXazR/+5tvYKsZQgyXJiwgpcva127YO6JcWy7YlCfofQ==", + "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": { - "@babel/runtime": "^7.12.5" + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" }, "engines": { - "node": ">=10", - "npm": ">=6" + "node": ">= 0.4" }, - "peerDependencies": { - "@testing-library/dom": ">=7.21.4" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, "engines": { - "node": ">= 6" + "node": ">= 0.4" } }, - "node_modules/@types/aria-query": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", - "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "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, - "peer": true - }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "node_modules/asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", "dependencies": { - "@babel/types": "^7.0.0" + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" } }, - "node_modules/@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "node_modules/asn1.js/node_modules/bn.js": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==" + }, + "node_modules/assert": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz", + "integrity": "sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==", "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" + "call-bind": "^1.0.2", + "is-nan": "^1.3.2", + "object-is": "^1.1.5", + "object.assign": "^4.1.4", + "util": "^0.12.5" } }, - "node_modules/@types/babel__traverse": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.1.tgz", - "integrity": "sha512-MitHFXnhtgwsGZWtT68URpOvLN4EREih1u3QtQiN4VdAxWKRVvGCSvw/Qth0M0Qq3pJpnGOu5JaM/ydK7OGbqg==", - "dependencies": { - "@babel/types": "^7.20.7" + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" } }, - "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/async-validator": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-3.5.2.tgz", + "integrity": "sha512-8eLCg00W9pIRZSB781UUX/H6Oskmm8xloZfr09lz5bikRpBVDlJ3hRVuxxP1SxcwsEYfJ4IU8Q19Y8/893r3rQ==", + "license": "MIT", + "peer": true }, - "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/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/@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/d3-color": "*" + "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": ">= 4.5.0" } }, - "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==", + "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": { - "@types/d3-time": "*" + "gulp-header": "^1.7.1" } }, - "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==", + "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==", "dependencies": { - "@types/d3-path": "*" + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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==", + "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, - "optional": true, - "peer": true, "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" + "@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": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" } }, - "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" + "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": "^14.15.0 || ^16.10.0 || >=18.0.0" + } }, - "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==", + "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": { - "@types/node": "*" + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@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==", + "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": { - "@types/unist": "*" + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@types/history": { - "version": "4.7.11", - "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", - "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==", + "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/@types/hoist-non-react-statics": { - "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==", + "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/react": "*", - "hoist-non-react-statics": "^3.3.0" + "@types/yargs-parser": "*" } }, - "node_modules/@types/inquirer": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/@types/inquirer/-/inquirer-9.0.7.tgz", - "integrity": "sha512-Q0zyBupO6NxGRZut/JdmqYKOnN95Eg5V8Csg3PGKkP+FnvsUZx1jAyK7fztIszxxMuoBA6E3KXWvdZVXIpx60g==", + "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": { - "@types/through": "*", - "rxjs": "^7.2.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "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==", + "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/@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==", + "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": { - "@types/istanbul-lib-coverage": "*" + "@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/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "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, - "dependencies": { - "@types/istanbul-lib-report": "*" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@types/jest": { - "version": "26.0.24", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.24.tgz", - "integrity": "sha512-E/X5Vib8BWqZNRlDxj9vYXhsDwPYbPINqKF9BsnSoon4RQ0D9moEuLD8txgyypFLH7J4+Lho9Nr/c8H0Fi+17w==", + "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": { - "jest-diff": "^26.0.0", - "pretty-format": "^26.0.0" - } - }, - "node_modules/@types/js-cookie": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@types/js-cookie/-/js-cookie-3.0.6.tgz", - "integrity": "sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==", - "dev": true - }, - "node_modules/@types/json-schema": { - "version": "7.0.12", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", - "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==" - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true - }, - "node_modules/@types/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": "*" + "@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": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@types/node": { - "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, + "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": { - "undici-types": "~6.19.2" + "@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/@types/node-fetch": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz", - "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==", + "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": { - "@types/node": "*", - "form-data": "^4.0.0" + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/@types/node-fetch/node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "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": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" }, "engines": { - "node": ">= 6" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@types/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" - }, - "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==", - "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/react": { - "version": "18.3.3", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", - "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", + "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": { - "@types/prop-types": "*", - "csstype": "^3.0.2" + "@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": ">=8" } }, - "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==", + "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": { - "@types/react": "*" + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@types/react-bootstrap": { - "version": "0.32.32", - "resolved": "https://registry.npmjs.org/@types/react-bootstrap/-/react-bootstrap-0.32.32.tgz", - "integrity": "sha512-GM9UtV7v+C2F0rbqgIpMWdCKBMdX3PQURoJQobPO4vDAeFadcExNtKffi13/MjaAks+riJKVGyiMe+6OmDYT2w==", - "dev": true, + "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": { - "@types/react": "*" + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" } }, - "node_modules/@types/react-datepicker": { - "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.", + "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": { - "react-datepicker": "*" + "@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/@types/react-dom": { - "version": "18.3.0", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", - "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==", + "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, - "dependencies": { - "@types/react": "*" + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/@types/react-google-recaptcha": { - "version": "2.1.9", - "resolved": "https://registry.npmjs.org/@types/react-google-recaptcha/-/react-google-recaptcha-2.1.9.tgz", - "integrity": "sha512-nT31LrBDuoSZJN4QuwtQSF3O89FVHC4jLhM+NtKEmVF5R1e8OY0Jo4//x2Yapn2aNHguwgX5doAq8Zo+Ehd0ug==", + "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": { - "@types/react": "*" + "@babel/helper-define-polyfill-provider": "^0.6.2", + "core-js-compat": "^3.38.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "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==", + "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": { - "@types/hoist-non-react-statics": "^3.3.0", - "@types/react": "*", - "hoist-non-react-statics": "^3.3.0", - "redux": "^4.0.0" + "@babel/helper-define-polyfill-provider": "^0.6.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "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==", + "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": { - "@babel/runtime": "^7.9.2" + "@babel/template": "^7.4.4", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@babel/core": "^7.10.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==", + "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": { - "@types/history": "^4.7.11", - "@types/react": "*" + "@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/@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==", + "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": { - "@types/history": "^4.7.11", - "@types/react": "*", - "@types/react-router": "*" + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "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==", + "node_modules/babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==", + "license": "MIT", + "peer": true, "dependencies": { - "@types/react": "*" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } }, - "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": { - "htmlparser2": "^8.0.0" - } + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, - "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/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/@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==", + "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==", "dev": true, - "dependencies": { - "@types/node": "*" + "engines": { + "node": ">=8" } }, - "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/bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" }, - "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": { - "@types/yargs-parser": "*" + "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/@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/@typescript-eslint/eslint-plugin": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.8.1.tgz", - "integrity": "sha512-xfvdgA8AP/vxHgtgU310+WBnLB4uJQ9XdyP17RebG26rLtDrQJV3ZYrcopX91GrHmMoH8bdSwMRh2a//TiJ1jQ==", + "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": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.8.1", - "@typescript-eslint/type-utils": "8.8.1", - "@typescript-eslint/utils": "8.8.1", - "@typescript-eslint/visitor-keys": "8.8.1", - "graphemer": "^1.4.0", - "ignore": "^5.3.1", - "natural-compare": "^1.4.0", - "ts-api-utils": "^1.3.0" + "ansi-align": "^3.0.0", + "camelcase": "^6.2.0", + "chalk": "^4.1.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": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "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, - "license": "BSD-2-Clause", - "dependencies": { - "@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": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "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, - "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.5.0", - "@typescript-eslint/visitor-keys": "8.5.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "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==", + "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, - "license": "MIT", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "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, - "license": "BSD-2-Clause", "dependencies": { - "@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" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "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==", + "dependencies": { + "fill-range": "^7.1.1" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=8" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" + }, + "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": { + "base64-js": "^1.1.2" + } + }, + "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/browser-resolve": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-2.0.0.tgz", + "integrity": "sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ==", + "dependencies": { + "resolve": "^1.17.0" + } + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dependencies": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "node_modules/browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dependencies": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/browserify-rsa": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.1.tgz", + "integrity": "sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==", + "dependencies": { + "bn.js": "^5.2.1", + "randombytes": "^2.1.0", + "safe-buffer": "^5.2.1" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/browserify-sign": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.3.tgz", + "integrity": "sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==", + "dependencies": { + "bn.js": "^5.2.1", + "browserify-rsa": "^4.1.0", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.5", + "hash-base": "~3.0", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.7", + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "engines": { + "node": ">= 0.12" } }, - "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", + "node_modules/browserify-sign/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/browserify-sign/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": { - "@typescript-eslint/types": "8.5.0", - "eslint-visitor-keys": "^3.4.3" + "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/browserify-sign/node_modules/readable-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/browserify-sign/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": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/browserify-sign/node_modules/string_decoder/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/browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "dependencies": { + "pako": "~1.0.5" + } + }, + "node_modules/browserslist": { + "version": "4.24.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", + "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001669", + "electron-to-chromium": "^1.5.41", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.1" }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "bin": { + "browserslist": "cli.js" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "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==", + "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": { + "node-int64": "^0.4.0" + } + }, + "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" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "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/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==" + }, + "node_modules/builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==" + }, + "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", - "dependencies": { - "balanced-match": "^1.0.0" + "bin": { + "bwip-js": "bin/bwip-js.js" } }, - "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==", + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, + "license": "MIT", "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=8" } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.8.1.tgz", - "integrity": "sha512-X4JdU+66Mazev/J0gfXlcC/dV6JI37h+93W9BRYXrSn0hrE64IoWgVkO9MSJgEzoWkxONgaQpICWg8vAN74wlA==", + "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": { - "@typescript-eslint/types": "8.8.1", - "@typescript-eslint/visitor-keys": "8.8.1" + "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": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=8" } }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.8.1.tgz", - "integrity": "sha512-qSVnpcbLP8CALORf0za+vjLYj1Wp8HSoiI8zYU5tHxRVj30702Z1Yw4cLwfNKhTPWp5+P+k1pjmD5Zd1nhxiZA==", + "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": { - "@typescript-eslint/typescript-estree": "8.8.1", - "@typescript-eslint/utils": "8.8.1", - "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" + "pump": "^3.0.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=8" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@typescript-eslint/types": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.8.1.tgz", - "integrity": "sha512-WCcTP4SDXzMd23N27u66zTKMuEevH4uzU8C9jf0RO4E04yVHgQgW+r+TeVTNnO1KIfrL8ebgVVYYMMO3+jC55Q==", + "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": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=8" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.8.1.tgz", - "integrity": "sha512-A5d1R9p+X+1js4JogdNilDuuq+EHZdsH9MjTVxXOdVFfTJXunKJR/v+fNNyO4TnoOn5HqobzfRlc70NC6HTcdg==", + "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, - "dependencies": { - "@typescript-eslint/types": "8.8.1", - "@typescript-eslint/visitor-keys": "8.8.1", - "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": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "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": { - "balanced-match": "^1.0.0" + "node": ">=8" } }, - "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, + "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==", "dependencies": { - "brace-expansion": "^2.0.1" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@typescript-eslint/utils": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.8.1.tgz", - "integrity": "sha512-/QkNJDbV0bdL7H7d0/y0qBbV2HTtf0TIyjSDTvvmQEzeVx8jEImEbLuOA4EsvE8gIgqMitns0ifb5uQhMj8d9w==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.8.1", - "@typescript-eslint/types": "8.8.1", - "@typescript-eslint/typescript-estree": "8.8.1" - }, + "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": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" + "node": ">=6" } }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.8.1.tgz", - "integrity": "sha512-0/TdC3aeRAsW7MDvYRwEc1Uwm0TIBfzjPFgg60UU2Haj5qsCs9cc3zNgY71edqE3LbWfF/WoZQd3lJoDXFQpag==", + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.8.1", - "eslint-visitor-keys": "^3.4.3" - }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=6" } }, - "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": { - "@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": "^14.18.0 || >=16.0.0" - }, - "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0" - } + "node_modules/caniuse-lite": { + "version": "1.0.30001680", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001680.tgz", + "integrity": "sha512-rPQy70G6AGUMnbwS1z6Xg+RkHYPAi18ihs47GH0jcxIG7wArmPgY3XbS2sRdBbxJljp3thdT8BIqv9ccCypiPA==", + "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/@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": ">=0.10.0" + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "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==", + "node_modules/chai": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.2.tgz", + "integrity": "sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==", + "dev": true, + "license": "MIT", "dependencies": { - "tslib": "^2.3.0" + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" }, "engines": { - "node": ">=8" + "node": ">=12" } }, - "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==", + "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": { - "tslib": "^2.3.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { "node": ">=8" } }, - "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": { - "tslib": "^2.3.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": ">=8" + "node": ">=10" } }, - "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": { - "tslib": "^2.3.0" - }, - "engines": { - "node": ">=8" + "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": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "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/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/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "license": "MIT" }, - "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" + "node_modules/chart.js": { + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.6.tgz", + "integrity": "sha512-8Y406zevUPbbIBA/HRk33khEmQPk5+cxeflWE/2rx1NJsjVWMPw/9mSP9rxHP5eqi6LNoPBVMfZHxbwLSgldYA==", + "license": "MIT", + "dependencies": { + "@kurkle/color": "^0.3.0" }, "engines": { - "node": ">=0.4.0" + "pnpm": ">=8" } }, - "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==", + "node_modules/check-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", + "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", "dev": true, - "dependencies": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" + "license": "MIT", + "engines": { + "node": ">= 16" } }, - "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==", + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", "dev": true, - "bin": { - "acorn": "bin/acorn" + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" }, "engines": { - "node": ">=0.4.0" - } - }, - "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": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" } }, - "node_modules/acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "node_modules/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": ">=0.4.0" + "node": ">=8" } }, - "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, + "node_modules/cipher-base": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.5.tgz", + "integrity": "sha512-xq7ICKB4TMHUx7Tz1L9O2SGKOhYMOTR32oir45Bq28/AQTpHogKgHcoYFSdRbMtddl+ozNXfXY9jWcgYKmde0w==", "dependencies": { - "debug": "4" + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1" }, "engines": { - "node": ">= 6.0.0" + "node": ">= 0.10" } }, - "node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "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.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", + "license": "MIT" + }, + "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, - "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": ">=6" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "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": { - "string-width": "^4.1.0" - } - }, - "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" + "restore-cursor": "^5.0.0" }, "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "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": { - "ansi-wrap": "0.1.0" + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "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": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "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": { - "color-convert": "^2.0.1" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "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": { + "ansi-regex": "^6.0.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "devOptional": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "license": "ISC", "engines": { - "node": ">= 8" + "node": ">= 12" } }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "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==", "dependencies": { - "sprintf-js": "~1.0.2" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" } }, - "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==", + "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": ">=0.8" + } + }, + "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": { - "dequal": "^2.0.3" + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", - "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "is-array-buffer": "^3.0.4" - }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=6" } }, - "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==", + "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, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.4", - "is-string": "^1.0.7" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" } }, - "node_modules/array.prototype.findlast": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", - "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-shim-unscopables": "^1.0.2" + "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": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.8.0" } }, - "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, + "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/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": { - "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" + "color-convert": "^2.0.1", + "color-string": "^1.9.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=12.5.0" } }, - "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, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" + "color-name": "~1.1.4" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=7.0.0" } }, - "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==", + "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/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": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "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/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": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" + "delayed-stream": "~1.0.0" }, "engines": { - "node": ">= 0.4" - }, + "node": ">= 0.8" + } + }, + "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": { - "url": "https://github.com/sponsors/ljharb" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "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==", + "node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.3", - "es-errors": "^1.3.0", - "es-shim-unscopables": "^1.0.2" - }, "engines": { - "node": ">= 0.4" + "node": "^12.20.0 || >=14" } }, - "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, + "node_modules/component-classes": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/component-classes/-/component-classes-1.2.6.tgz", + "integrity": "sha512-hPFGULxdwugu1QWW3SvVOCUHLzO34+a2J6Wqy0c5ASQkfi9/8nZcBB0ZohaEbXOQlCflMAEMmEWk7u7BVs4koA==", + "license": "MIT", + "peer": true, "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.2.1", - "get-intrinsic": "^1.2.3", - "is-array-buffer": "^3.0.4", - "is-shared-array-buffer": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "component-indexof": "0.0.3" } }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "node_modules/component-indexof": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-indexof/-/component-indexof-0.0.3.tgz", + "integrity": "sha512-puDQKvx/64HZXb4hBwIcvQLaLgux8o1CbWl39s41hrIIZDl1lJiD5jc22gj3RBeGK0ovxALDYpIbyjqDUUl0rw==", + "peer": true + }, + "node_modules/compute-scroll-into-view": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.1.0.tgz", + "integrity": "sha512-rj8l8pD4bJ1nx+dAkMhV1xB5RuZEyVysfxJqB1pRchh1KVvwOv9b7CGB8ZfjTImVv2oF+sYMUkMZq6Na5Ftmbg==", + "license": "MIT", + "peer": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, - "node_modules/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": ">= 4.5.0" + "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": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "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/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/autolinker": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/autolinker/-/autolinker-0.28.1.tgz", - "integrity": "sha512-zQAFO1Dlsn69eXaO6+7YZc+v84aquQKbwpzCE3L0stj56ERn9hutFxPopViLjo9G+rWwjozRhgS5KJ25Xy19cQ==", + "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": { - "gulp-header": "^1.7.1" + "safe-buffer": "~5.1.0" } }, - "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, + "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": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "source-map": "^0.6.1" } }, - "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": { - "@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" - }, + "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": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" + "node": ">=0.10.0" } }, - "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==", + "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": { - "@sinclair/typebox": "^0.27.8" + "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" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=8" } }, - "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==", + "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": { - "@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" + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 0.10.0" } }, - "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==", + "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": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "ms": "2.0.0" } }, - "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==", + "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/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, + "node_modules/console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==" + }, + "node_modules/constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==" + }, + "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/copy-to-clipboard": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz", + "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==", + "license": "MIT", + "peer": true, "dependencies": { - "@types/yargs-parser": "*" + "toggle-selection": "^1.0.6" } }, - "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==", + "node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "hasInstallScript": true, + "license": "MIT", + "peer": true + }, + "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": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" + "browserslist": "^4.23.3" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/core-js" } }, - "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/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/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, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", "dependencies": { - "@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" + "@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": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" + "node": ">=10" } }, - "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/create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "dependencies": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" } }, - "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, + "node_modules/create-ecdh/node_modules/bn.js": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==" + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "dependencies": { - "@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": "^14.15.0 || ^16.10.0 || >=18.0.0" + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" } }, - "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==", + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/create-react-class": { + "version": "15.7.0", + "resolved": "https://registry.npmjs.org/create-react-class/-/create-react-class-15.7.0.tgz", + "integrity": "sha512-QZv4sFWG9S5RUvkTYWbflxeZX+JG7Cz0Tn33rQBJ+WFQTqTfUTjMjiv9tnfXazjsO5r0KhPs+AqCjyrQX6h2ng==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.3.1", + "object-assign": "^4.1.1" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" + }, + "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": { - "@types/node": "*", - "jest-util": "^29.7.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.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": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" } }, - "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, + "node_modules/cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "node-fetch": "^2.6.12" } }, - "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==", + "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": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">= 8" } }, - "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, + "node_modules/crypto-browserify": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.1.tgz", + "integrity": "sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==", "dependencies": { - "@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" + "browserify-cipher": "^1.0.1", + "browserify-sign": "^4.2.3", + "create-ecdh": "^4.0.4", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "diffie-hellman": "^5.0.3", + "hash-base": "~3.0.4", + "inherits": "^2.0.4", + "pbkdf2": "^3.1.2", + "public-encrypt": "^4.0.3", + "randombytes": "^2.1.0", + "randomfill": "^1.0.4" }, "engines": { - "node": ">=8" + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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==", + "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, - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=8" } }, - "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==", + "node_modules/css-animation": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/css-animation/-/css-animation-1.6.1.tgz", + "integrity": "sha512-/48+/BaEaHRY6kNQ2OIPzKf9A6g8WjZYjhiNDNuIVbsm5tXCGIAsHDjB4Xu1C4vXJtUWZo26O68OQkDpNBaPog==", + "license": "MIT", + "peer": true, "dependencies": { - "@babel/runtime": "^7.12.5", - "cosmiconfig": "^7.0.0", - "resolve": "^1.19.0" - }, - "engines": { - "node": ">=10", - "npm": ">=6" + "babel-runtime": "6.x", + "component-classes": "^1.2.5" } }, - "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, + "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": { - "@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" + "tiny-invariant": "^1.0.6" } }, - "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==", + "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": { - "semver": "bin/semver.js" + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" } }, - "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==", + "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/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", "dev": true, "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.2", - "core-js-compat": "^3.38.0" + "cssom": "~0.3.6" }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + "engines": { + "node": ">=8" } }, - "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, + "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/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": { - "@babel/helper-define-polyfill-provider": "^0.6.2" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + "lodash.flow": "^3.5.0" } }, - "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==", + "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": { - "@babel/template": "^7.4.4", - "tslib": "^2.4.0" + "internmap": "1 - 2" }, - "peerDependencies": { - "@babel/core": "^7.10.0" + "engines": { + "node": ">=12" } }, - "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": { - "@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/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": ">=12" } }, - "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, + "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": { - "babel-plugin-jest-hoist": "^29.6.3", - "babel-preset-current-node-syntax": "^1.0.0" + "delaunator": "5" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node": ">=12" } }, - "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/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/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/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": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } }, - "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, + "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": ">=8" + "node": ">=12" } }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "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": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.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": ">=12" } }, - "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": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], + "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": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" } }, - "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/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": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" } }, - "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, + "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": { - "ansi-align": "^3.0.0", - "camelcase": "^6.2.0", - "chalk": "^4.1.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" + "d3-time": "1 - 3" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=12" } }, - "node_modules/boxen/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "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": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + }, "engines": { "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "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": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "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==", + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", "dev": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "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": { - "fill-range": "^7.1.1" + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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": { - "base64-js": "^1.1.2" + "node_modules/date-fns": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" } }, - "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/dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==" }, - "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" - } - ], + "node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dependencies": { - "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" + "ms": "^2.1.3" }, "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "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": { - "node-int64": "^0.4.0" - } - }, - "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" + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true } - ], - "peer": true, + } + }, + "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/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": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" + "mimic-response": "^1.0.0" + }, + "engines": { + "node": ">=4" } }, - "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/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/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==", + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, "license": "MIT", - "peer": true, - "bin": { - "bwip-js": "bin/bwip-js.js" + "engines": { + "node": ">=6" } }, - "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==", + "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, - "dependencies": { - "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": ">=8" + "node": ">=4.0.0" } }, - "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, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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==", "dependencies": { - "pump": "^3.0.0" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" }, "engines": { - "node": ">=8" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/cacheable-request/node_modules/lowercase-keys": { + "node_modules/define-lazy-prop": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "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==", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", "dev": true, "engines": { "node": ">=8" } }, - "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, + "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==", "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" }, "engines": { "node": ">= 0.4" @@ -6552,1966 +9602,2047 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "engines": { - "node": ">=6" + "node_modules/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/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "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": ">=6" + "node": ">=0.4.0" } }, - "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/ccount": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", - "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "engines": { + "node": ">=6" } }, - "node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, + "node_modules/des.js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", + "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" + "inherits": "^2.0.1", + "minimalistic-assert": "^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==", + "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": ">=10" + "node": ">=0.10.0" } }, - "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": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "optional": true, + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" } }, - "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==", + "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": { + "dequal": "^2.0.0" + }, "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, - "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/dfa": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/dfa/-/dfa-1.2.0.tgz", + "integrity": "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==" }, - "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": { - "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" - }, + "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": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "node": ">=0.8.0" } }, - "node_modules/ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", + "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, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], "engines": { - "node": ">=8" + "node": ">= 10.14.2" } }, - "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/diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dependencies": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } }, - "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/diffie-hellman/node_modules/bn.js": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==" }, - "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==", + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, - "engines": { - "node": ">=6" + "dependencies": { + "esutils": "^2.0.2" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=6.0.0" } }, - "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==", + "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/dom-align": { + "version": "1.12.4", + "resolved": "https://registry.npmjs.org/dom-align/-/dom-align-1.12.4.tgz", + "integrity": "sha512-R8LUSEay/68zE5c8/3BDxiTEvgb4xZTF0RKmAHfiEVN3klfIpXfi2/QCoiWPccVQ0J/ZGdz9OjzL4uJEP/MRAw==", + "license": "MIT", + "peer": true + }, + "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": { - "restore-cursor": "^5.0.0" - }, - "engines": { - "node": ">=18" + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" } }, - "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==", + "node_modules/domain-browser": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-4.23.0.tgz", + "integrity": "sha512-ArzcM/II1wCCujdCNyQjXrAFwS4mrLh4C7DZWlaI8mdh7h3BfKdNd3bKXITfl2PT9FtfQqaGvhi1vPRQPimjGA==", "engines": { - "node": ">=6" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://bevry.me/fund" } }, - "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==", + "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/domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", "dev": true, "dependencies": { - "slice-ansi": "^5.0.0", - "string-width": "^7.0.0" + "webidl-conversions": "^5.0.0" }, "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, - "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==", + "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": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "node": ">=8" } }, - "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, + "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": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" + "domelementtype": "^2.3.0" }, "engines": { - "node": ">=18" + "node": ">= 4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/fb55/domhandler?sponsor=1" } }, - "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, + "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": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" }, "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "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": ">= 10" + "url": "https://github.com/fb55/domutils?sponsor=1" } }, - "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==", + "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": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.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": ">=0.8" + "no-case": "^3.0.4", + "tslib": "^2.0.3" } }, - "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==", + "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": { - "mimic-response": "^1.0.0" + "is-obj": "^2.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": ">=8" } }, - "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, + "node_modules/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.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" + "node": ">=12" }, - "engines": { - "node": ">=0.8.0" + "funding": { + "url": "https://dotenvx.com" } }, - "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==", + "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/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "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/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": { - "color-convert": "^2.0.1", - "color-string": "^1.9.0" - }, + "node_modules/electron-to-chromium": { + "version": "1.5.62", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.62.tgz", + "integrity": "sha512-t8c+zLmJHa9dJy96yBZRXGQYoiCEnHYgFwn1asvSPZSUdVxnB62A4RASd7k41ytG3ErFBA0TpHlKg9D9SQBmLg==" + }, + "node_modules/elliptic": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", + "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==" + }, + "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, "engines": { - "node": ">=12.5.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" } }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "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": ">=7.0.0" + "node": ">= 0.8" } }, - "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/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", + "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": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" + "iconv-lite": "^0.6.2" } }, - "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/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "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": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" + "once": "^1.4.0" } }, - "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==", + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/commander": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", - "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "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": "^12.20.0 || >=14" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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/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" - ], + "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": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" + "is-arrayish": "^0.2.1" } }, - "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/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==", + "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": { - "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" + "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/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==", + "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==", "dependencies": { - "safe-buffer": "~5.1.0" + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" } }, - "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/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" } }, - "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==", + "node_modules/es-iterator-helpers": { + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz", + "integrity": "sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.3", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "iterator.prototype": "^1.1.2", + "safe-array-concat": "^1.1.2" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" } }, - "node_modules/configstore": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", - "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "node_modules/es-module-lexer": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", + "dev": true, + "license": "MIT" + }, + "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": { - "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" + "es-errors": "^1.3.0" }, "engines": { - "node": ">=8" + "node": ">= 0.4" } }, - "node_modules/connect": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", - "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "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": { - "debug": "2.6.9", - "finalhandler": "1.1.2", - "parseurl": "~1.3.3", - "utils-merge": "1.0.1" + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" }, "engines": { - "node": ">= 0.10.0" + "node": ">= 0.4" } }, - "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==", + "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": { - "ms": "2.0.0" + "hasown": "^2.0.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/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/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==", + "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": { - "browserslist": "^4.23.3" + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/core-util-is": { + "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": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/esbuild/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" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "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": ">=6" + } + }, + "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": ">=8" + } + }, + "node_modules/escape-html": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true }, - "node_modules/cosmiconfig": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", - "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cross-env": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", - "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", "dev": true, "dependencies": { - "cross-spawn": "^7.0.1" + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" }, "bin": { - "cross-env": "src/bin/cross-env.js", - "cross-env-shell": "src/bin/cross-env-shell.js" + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/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, + "engines": { + "node": ">=0.10.0" + } + }, + "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", + "dependencies": { + "@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" + }, + "bin": { + "eslint": "bin/eslint.js" }, "engines": { - "node": ">=10.14", - "npm": ">=6", - "yarn": ">=1" - } - }, - "node_modules/cross-fetch": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", - "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", - "dependencies": { - "node-fetch": "^2.6.12" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "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==", + "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, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "bin": { + "eslint-config-prettier": "bin/cli.js" }, - "engines": { - "node": ">= 8" + "peerDependencies": { + "eslint": ">=7.0.0" } }, - "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==", + "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, - "engines": { - "node": ">=8" - } - }, - "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": { - "tiny-invariant": "^1.0.6" + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" } }, - "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==", + "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, - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" + "dependencies": { + "ms": "^2.1.1" } }, - "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/cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "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": { - "cssom": "~0.3.6" + "debug": "^3.2.7" }, "engines": { - "node": ">=8" + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } } }, - "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/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==", + "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": { - "lodash.flow": "^3.5.0" + "ms": "^2.1.1" } }, - "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==", + "node_modules/eslint-plugin-import": { + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz", + "integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==", + "dev": true, "dependencies": { - "internmap": "1 - 2" + "@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.12.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", + "string.prototype.trimend": "^1.0.8", + "tsconfig-paths": "^3.15.0" }, "engines": { - "node": ">=12" + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" } }, - "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": ">=12" + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" } }, - "node_modules/d3-delaunay": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", - "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "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": { - "delaunator": "5" + "esutils": "^2.0.2" }, "engines": { - "node": ">=12" + "node": ">=0.10.0" } }, - "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/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/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==", + "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": { - "d3-color": "1 - 3" + "@typescript-eslint/utils": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "engines": { - "node": ">=12" - } - }, - "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": ">=12" + "node": "^16.10.0 || ^18.12.0 || >=20.0.0" + }, + "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": "*" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + }, + "jest": { + "optional": true + } } }, - "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==", + "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": { - "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" + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.9.1" }, "engines": { - "node": ">=12" - } - }, - "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": { - "d3-path": "^3.1.0" + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": "*", + "prettier": ">=3.0.0" }, - "engines": { - "node": ">=12" + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } } }, - "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==", + "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, "dependencies": { - "d3-array": "2 - 3" + "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": ">=12" + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, - "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==", + "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": { - "d3-time": "1 - 3" + "esutils": "^2.0.2" }, "engines": { - "node": ">=12" + "node": ">=0.10.0" } }, - "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==", + "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, - "dependencies": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" - }, "engines": { - "node": ">=10" + "node": ">=4.0" } }, - "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==", + "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": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" }, - "engines": { - "node": ">= 0.4" + "bin": { + "resolve": "bin/resolve" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/data-view-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", - "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-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": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, + "@microsoft/tsdoc": "0.15.0", + "@microsoft/tsdoc-config": "0.17.0" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", "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/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==", + "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, "dependencies": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" + "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": { - "url": "https://github.com/sponsors/ljharb" + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "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, + "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 + }, + "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, "dependencies": { - "@babel/runtime": "^7.21.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=0.11" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/date-fns" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/dayjs": { - "version": "1.11.13", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", - "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==" - }, - "node_modules/debug": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "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", "dependencies": { - "ms": "2.1.2" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" }, "engines": { - "node": ">=6.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "funding": { + "url": "https://opencollective.com/eslint" } }, - "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/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==", + "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, - "dependencies": { - "mimic-response": "^1.0.0" - }, + "license": "BSD-2-Clause", "engines": { - "node": ">=4" + "node": ">=4.0" } }, - "node_modules/dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", - "dev": true - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, "engines": { - "node": ">=4.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "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 - }, - "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==", + "dependencies": { + "is-glob": "^4.0.3" + }, "engines": { - "node": ">=0.10.0" + "node": ">=10.13.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==", + "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, "dependencies": { - "clone": "^1.0.2" + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "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/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, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "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==", + "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 }, - "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==", + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" + "p-locate": "^5.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "node_modules/eslint/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" + "p-limit": "^3.0.2" }, "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "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, "engines": { - "node": ">=0.4.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "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", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, "engines": { - "node": ">=6" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "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, + "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": ">=0.10.0" + "node": ">=4" } }, - "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==", + "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, "dependencies": { - "dequal": "^2.0.0" + "estraverse": "^5.1.0" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "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/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": ">=0.8.0" + "node": ">=0.10" } }, - "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==", + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, "engines": { - "node": ">= 10.14.2" + "node": ">=4.0" } }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "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": { - "esutils": "^2.0.2" + "estraverse": "^5.2.0" }, "engines": { - "node": ">=6.0.0" + "node": ">=4.0" } }, - "node_modules/dom-accessibility-api": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", - "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "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/dom-helpers": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", - "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.8.7", - "csstype": "^3.0.2" + "@types/estree": "^1.0.0" } }, - "node_modules/dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + "node_modules/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/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/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/domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "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": { - "webidl-conversions": "^5.0.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": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "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==", + "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": ">=8" + "node": ">= 0.8.0" } }, - "node_modules/domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "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": { - "domelementtype": "^2.3.0" + "fill-range": "^2.1.0" }, "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" + "node": ">=0.10.0" } }, - "node_modules/domutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", - "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "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": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" + "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/fb55/domutils?sponsor=1" + "engines": { + "node": ">=0.10.0" } }, - "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, + "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": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" } }, - "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, + "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": { - "is-obj": "^2.0.0" + "isarray": "1.0.0" }, "engines": { - "node": ">=8" + "node": ">=0.10.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": ">=12" + "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://dotenvx.com" - } - }, - "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/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, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" + "node": ">=0.10.0" } }, - "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==", + "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, - "engines": { - "node": ">= 0.8" - } - }, - "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": { - "iconv-lite": "^0.6.2" + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "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==", + "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==", "dev": true, "dependencies": { - "once": "^1.4.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.12" + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/environment": { + "node_modules/expect-type": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", - "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.1.0.tgz", + "integrity": "sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==", "dev": true, "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=12.0.0" } }, - "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==", + "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==", + "license": "MIT", "dependencies": { - "is-arrayish": "^0.2.1" + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" } }, - "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, + "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==", + "license": "MIT", "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "arraybuffer.prototype.slice": "^1.0.3", - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "data-view-buffer": "^1.0.1", - "data-view-byte-length": "^1.0.1", - "data-view-byte-offset": "^1.0.0", - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-set-tostringtag": "^2.0.3", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.4", - "get-symbol-description": "^1.0.2", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.3", - "has-symbols": "^1.0.3", - "hasown": "^2.0.2", - "internal-slot": "^1.0.7", - "is-array-buffer": "^3.0.4", - "is-callable": "^1.2.7", - "is-data-view": "^1.0.1", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.3", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.13", - "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", - "object-keys": "^1.1.1", - "object.assign": "^4.1.5", - "regexp.prototype.flags": "^1.5.2", - "safe-array-concat": "^1.1.2", - "safe-regex-test": "^1.0.3", - "string.prototype.trim": "^1.2.9", - "string.prototype.trimend": "^1.0.8", - "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.2", - "typed-array-byte-length": "^1.0.1", - "typed-array-byte-offset": "^1.0.2", - "typed-array-length": "^1.0.6", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.15" + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "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==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8.6.0" } }, - "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, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fast-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", "dependencies": { - "get-intrinsic": "^1.2.4" + "strnum": "^1.0.5" }, - "engines": { - "node": ">= 0.4" + "bin": { + "fxparser": "src/cli/cli.js" } }, - "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==", + "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==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "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, - "engines": { - "node": ">= 0.4" + "dependencies": { + "bser": "2.1.1" } }, - "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==", + "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, "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.3", - "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.0.3", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "globalthis": "^1.0.3", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.3", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.7", - "iterator.prototype": "^1.1.2", - "safe-array-concat": "^1.1.2" + "flat-cache": "^3.0.4" }, "engines": { - "node": ">= 0.4" + "node": "^10.12.0 || >=12.0.0" } }, - "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, + "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==", "dependencies": { - "es-errors": "^1.3.0" + "to-regex-range": "^5.0.1" }, "engines": { - "node": ">= 0.4" + "node": ">=8" } }, - "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==", + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", "dev": true, "dependencies": { - "get-intrinsic": "^1.2.4", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.1" + "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": ">= 0.4" + "node": ">= 0.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==", + "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": { - "hasown": "^2.0.0" + "ms": "2.0.0" } }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "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": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/esbuild": { - "version": "0.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": ">=12" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" + "findup-sync": "^4.0.0", + "merge": "^2.1.1" } }, - "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": ">=6" - } + "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/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==", + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, "engines": { "node": ">=8" } }, - "node_modules/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": { + "node_modules/findup-sync": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "engines": { - "node": ">=10" + "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/sponsors/sindresorhus" + "engines": { + "node": ">= 8" } }, - "node_modules/escodegen": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", - "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "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, "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" + "flatted": "^3.1.0", + "rimraf": "^3.0.2" }, "engines": { - "node": ">=6.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" + "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/escodegen/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" + "node_modules/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 + }, + "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/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, + "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" } }, - "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "node_modules/foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", "dev": true, - "license": "MIT", - "peer": true, "dependencies": { - "@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" - }, - "bin": { - "eslint": "bin/eslint.js" + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=14" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/isaacs" } }, - "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==", + "node_modules/foreground-child/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, - "bin": { - "eslint-config-prettier": "bin/cli.js" + "engines": { + "node": ">=14" }, - "peerDependencies": { - "eslint": ">=7.0.0" + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "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/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": { - "debug": "^3.2.7", - "is-core-module": "^2.13.0", - "resolve": "^1.22.4" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" } }, - "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, + "node_modules/form-render": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-render/-/form-render-2.5.1.tgz", + "integrity": "sha512-oNbJ+McqB5h1yuyxYAT3ixJF8itmHlnKvqDgQhJT9Tw1c3yGwfRnVXboRxBV+Myz0dkf47zL6lyY1l74yQsWsg==", + "license": "MIT", + "peer": true, "dependencies": { - "ms": "^2.1.1" + "@ant-design/icons": "^4.0.2", + "ahooks": "^3.7.5", + "async-validator": "^3.5.1", + "classnames": "^2.3.1", + "color": "^3.1.2", + "dayjs": "^1.11.7", + "lodash-es": "^4.17.21", + "rc-color-picker": "^1.2.6", + "virtualizedtableforantd4": "^1.1.2", + "zustand": "^4.1.5" + }, + "peerDependencies": { + "antd": "4.x || 5.x", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" } }, - "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, + "node_modules/form-render/node_modules/@ant-design/colors": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-6.0.0.tgz", + "integrity": "sha512-qAZRvPzfdWHtfameEGP2Qvuf838NhergR35o+EuVyB5XvSA98xod5r4utvi4TJ3ywmevm290g9nsCG5MryrdWQ==", + "license": "MIT", + "peer": true, "dependencies": { - "debug": "^3.2.7" + "@ctrl/tinycolor": "^3.4.0" + } + }, + "node_modules/form-render/node_modules/@ant-design/icons": { + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-4.8.3.tgz", + "integrity": "sha512-HGlIQZzrEbAhpJR6+IGdzfbPym94Owr6JZkJ2QCCnOkPVIWMO2xgIVcOKnl8YcpijIo39V7l2qQL5fmtw56cMw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@ant-design/colors": "^6.0.0", + "@ant-design/icons-svg": "^4.3.0", + "@babel/runtime": "^7.11.2", + "classnames": "^2.2.6", + "lodash": "^4.17.15", + "rc-util": "^5.9.4" }, "engines": { - "node": ">=4" + "node": ">=8" }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } + "peerDependencies": { + "react": ">=16.0.0", + "react-dom": ">=16.0.0" } }, - "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, + "node_modules/form-render/node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "license": "MIT", + "peer": true, "dependencies": { - "ms": "^2.1.1" + "color-convert": "^1.9.3", + "color-string": "^1.6.0" } }, - "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, + "node_modules/form-render/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==", + "license": "MIT", + "peer": true, "dependencies": { - "@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": ">=4" + "color-name": "1.1.3" + } + }, + "node_modules/form-render/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==", + "license": "MIT", + "peer": true + }, + "node_modules/form-render/node_modules/rc-color-picker": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/rc-color-picker/-/rc-color-picker-1.2.6.tgz", + "integrity": "sha512-AaC9Pg7qCHSy5M4eVbqDIaNb2FC4SEw82GOHB2C4R/+vF2FVa/r5XA+Igg5+zLPmAvBLhz9tL4MAfkRA8yWNJw==", + "license": "MIT", + "peer": true, + "dependencies": { + "classnames": "^2.2.5", + "prop-types": "^15.5.8", + "rc-trigger": "1.x", + "rc-util": "^4.0.2", + "tinycolor2": "^1.4.1" }, "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + "react": "16.x", + "react-dom": "16.x" } }, - "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, + "node_modules/form-render/node_modules/rc-color-picker/node_modules/rc-util": { + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-4.21.1.tgz", + "integrity": "sha512-Z+vlkSQVc1l8O2UjR3WQ+XdWlhj5q9BMQNLk2iOBch75CqPfrJyGtcWMcnhRlNuDu0Ndtt4kLVO8JI8BrABobg==", + "license": "MIT", + "peer": true, "dependencies": { - "ms": "^2.1.1" + "add-dom-event-listener": "^1.1.0", + "prop-types": "^15.5.10", + "react-is": "^16.12.0", + "react-lifecycles-compat": "^3.0.4", + "shallowequal": "^1.1.0" } }, - "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": { - "esutils": "^2.0.2" - }, + "node_modules/form-render/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==", + "license": "MIT", + "peer": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/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" + ], "engines": { - "node": ">=0.10.0" + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "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/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/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==", + "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, - "license": "MIT", "dependencies": { - "@typescript-eslint/utils": "^6.0.0 || ^7.0.0 || ^8.0.0" + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" }, "engines": { - "node": "^16.10.0 || ^18.12.0 || >=20.0.0" - }, - "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": "*" + "node": ">= 0.4" }, - "peerDependenciesMeta": { - "@typescript-eslint/eslint-plugin": { - "optional": true - }, - "jest": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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==", + "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, - "dependencies": { - "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.9.1" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, "funding": { - "url": "https://opencollective.com/eslint-plugin-prettier" - }, - "peerDependencies": { - "@types/eslint": ">=8.0.0", - "eslint": ">=8.0.0", - "eslint-config-prettier": "*", - "prettier": ">=3.0.0" - }, - "peerDependenciesMeta": { - "@types/eslint": { - "optional": true - }, - "eslint-config-prettier": { - "optional": true - } + "url": "https://github.com/sponsors/ljharb" } }, - "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==", + "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": { - "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" - }, + "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==", "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" + "node": ">=6.9.0" } }, - "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" - }, + "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==", "engines": { - "node": ">=0.10.0" + "node": "6.* || 8.* || >= 10.*" } }, - "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==", + "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": ">=4.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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, + "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==", "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^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" }, - "bin": { - "resolve": "bin/resolve" + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/eslint-plugin-react/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-plugin-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==", + "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, - "dependencies": { - "@microsoft/tsdoc": "0.15.0", - "@microsoft/tsdoc-config": "0.17.0" + "engines": { + "node": ">=8.0.0" } }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "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, - "license": "Apache-2.0", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=10" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "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, - "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" + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "url": "https://github.com/sponsors/ljharb" } }, - "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==", + "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, - "peer": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" + "resolve-pkg-maps": "^1.0.0" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, - "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==", + "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, - "license": "BSD-2-Clause", - "peer": true, "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "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": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "*" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/isaacs" } }, - "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, + "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": ">=4.0" + "node": ">= 6" } }, - "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/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, - "peer": true, "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "ini": "2.0.0" }, "engines": { "node": ">=10" @@ -8520,755 +11651,762 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "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, - "peer": true, - "dependencies": { - "is-glob": "^4.0.3" - }, "engines": { - "node": ">=10.13.0" + "node": ">=10" } }, - "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/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", "dev": true, - "peer": true, "dependencies": { - "type-fest": "^0.20.2" + "define-properties": "^1.1.3" }, "engines": { - "node": ">=8" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "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, + "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/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", "dependencies": { - "argparse": "^2.0.1" + "get-intrinsic": "^1.1.3" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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==", + "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, - "peer": true, "dependencies": { - "p-locate": "^5.0.0" + "@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" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8.6" } }, - "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/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, - "peer": true, "dependencies": { - "yocto-queue": "^0.1.0" + "pump": "^3.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=6" } }, - "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, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/graphql": { + "version": "16.9.0", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.9.0.tgz", + "integrity": "sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==", + "engines": { + "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.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": { - "p-limit": "^3.0.2" + "tslib": "^2.1.0" }, "engines": { "node": ">=10" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "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/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, + "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/sponsors/sindresorhus" + "peerDependencies": { + "graphql": ">=0.11 <=16" } }, - "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, + "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": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" + "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": ">=4" + "node": ">=0.10.0" } }, - "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, + "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": { - "estraverse": "^5.1.0" + "is-extendable": "^0.1.0" }, "engines": { - "node": ">=0.10" + "node": ">=0.10.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==", - "dev": true, - "peer": true, + "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": ">=4.0" + "node": ">=0.10.0" } }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "peer": true, + "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": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" + "concat-with-sourcemaps": "*", + "lodash.template": "^4.4.0", + "through2": "^2.0.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/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, - "peer": true, - "engines": { - "node": ">=4.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, + "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==", "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" + "es-define-property": "^1.0.0" }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "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, + "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==", "engines": { - "node": ">= 0.8.0" + "node": ">= 0.4" + }, + "funding": { + "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/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dependencies": { - "fill-range": "^2.1.0" + "has-symbols": "^1.0.3" }, "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==", - "dependencies": { - "is-number": "^2.1.0", - "isobject": "^2.0.0", - "randomatic": "^3.0.0", - "repeat-element": "^1.1.2", - "repeat-string": "^1.5.2" - }, + "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": ">=0.10.0" + "node": ">=8" } }, - "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/hash-base": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", + "integrity": "sha512-EeeoJKjTyt868liAlVmcv2ZsUfGHlE3Q+BICOXcZiwN3osr5Q/zFGYmTJpoIzuaSTAwndFy+GqhEwlU4L3j4Ow==", "dependencies": { - "kind-of": "^3.0.2" + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "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/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } }, - "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/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dependencies": { - "isarray": "1.0.0" + "function-bind": "^1.1.2" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" } }, - "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/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": { - "is-buffer": "^1.1.5" + "@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" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "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, + "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": { - "homedir-polyfill": "^1.0.1" + "@types/hast": "^3.0.0" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "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==", - "dev": true, + "node_modules/history": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/history/-/history-5.3.0.tgz", + "integrity": "sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==", "dependencies": { - "@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" + "@babel/runtime": "^7.7.6" } }, - "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/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", "dependencies": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - }, - "engines": { - "node": ">=4" + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" } }, - "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/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, "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "parse-passwd": "^1.0.0" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "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==", + "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, - "license": "MIT", "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" + "whatwg-encoding": "^1.0.5" }, "engines": { - "node": ">=8.6.0" + "node": ">=10" } }, - "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==", + "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/NaturalIntelligence" + "url": "https://github.com/sponsors/mdevils" }, { - "type": "paypal", - "url": "https://paypal.me/naturalintelligence" + "type": "patreon", + "url": "https://patreon.com/mdevils" } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "strnum": "^1.0.5" - }, - "bin": { - "fxparser": "src/cli/cli.js" - } - }, - "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/fb-watchman": { + "node_modules/html-escaper": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "dev": true, + "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": { - "bser": "2.1.1" + "void-elements": "3.1.0" } }, - "node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=8" - }, + "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": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "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": ">=0.8.0" + "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/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/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, - "peer": true, "dependencies": { - "flat-cache": "^3.0.4" + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">= 6" } }, - "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": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } + "node_modules/https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==" }, - "node_modules/finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "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": { - "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" + "agent-base": "6", + "debug": "4" }, "engines": { - "node": ">= 0.8" + "node": ">= 6" } }, - "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/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, - "dependencies": { - "ms": "2.0.0" + "engines": { + "node": ">=10.17.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-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==", + "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, - "dependencies": { - "findup-sync": "^4.0.0", - "merge": "^2.1.1" + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" } }, - "node_modules/find-root": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", - "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, + "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": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" + "@babel/runtime": "^7.23.2" } }, - "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, + "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": { - "detect-file": "^1.0.0", - "is-glob": "^4.0.0", - "micromatch": "^4.0.2", - "resolve-dir": "^1.0.1" - }, - "engines": { - "node": ">= 8" + "@babel/runtime": "^7.23.2" } }, - "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/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": { + "cross-fetch": "4.0.0" + } }, - "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, + "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": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=0.10.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/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, - "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" + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.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==", + "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, + "license": "MIT", "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==", + "harmony-reflect": "^1.4.6" + }, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "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/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, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, + "license": "MIT", "engines": { - "node": ">= 6" + "node": ">= 4" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "node_modules/immer": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.1.tgz", + "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==", "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/immer" } }, - "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, + "node_modules/immutable": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.0.2.tgz", + "integrity": "sha512-1NU7hWZDkV7hJ4PJ9dur9gTNQ4ePNPN4k9/0YhwjzykTi/+3Q5pF93YU5QoVj8BuOnhLgaY8gs0U2pj4kSYVcw==", + "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": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=6" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "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, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=4" } }, - "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/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": { - "loader-utils": "^3.2.0" + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "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": ">=6.9.0" + "node": ">=0.8.19" } }, - "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/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": "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/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/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/inquirer": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-11.1.0.tgz", + "integrity": "sha512-CmLAZT65GG/v30c+D2Fk8+ceP6pxD6RL+hIUOWAltCmeyEqWYwqu9v76q03OvjyZ3AB0C1Ala2stn1z/rMqGEw==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^9.2.1", + "@inquirer/prompts": "^6.0.1", + "@inquirer/type": "^2.0.0", + "@types/mute-stream": "^0.0.4", + "ansi-escapes": "^4.3.2", + "mute-stream": "^1.0.0", + "run-async": "^3.0.0", + "rxjs": "^7.8.1" + }, "engines": { "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "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/internal-slot": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", "dev": true, "dependencies": { "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "hasown": "^2.0.0", + "side-channel": "^1.0.4" }, "engines": { "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, - "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, + "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": ">=8.0.0" + "node": ">=12" } }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node_modules/intersection-observer": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/intersection-observer/-/intersection-observer-0.12.2.tgz", + "integrity": "sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg==", + "license": "Apache-2.0", + "peer": true + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dependencies": { + "loose-envify": "^1.0.0" } }, - "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, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", "dependencies": { - "call-bind": "^1.0.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4" + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -9277,89 +12415,74 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-tsconfig": { - "version": "4.7.5", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.5.tgz", - "integrity": "sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==", + "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": { - "resolve-pkg-maps": "^1.0.0" + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "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": { - "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" + "has-tostringtag": "^1.0.0" }, "engines": { - "node": "*" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "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": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" + "url": "https://github.com/sponsors/ljharb" } }, - "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==", + "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": { - "ini": "2.0.0" - }, - "engines": { - "node": ">=10" + "has-bigints": "^1.0.1" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "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/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, "engines": { - "node": ">=10" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "engines": { - "node": ">=4" + "node": ">=8" } }, - "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/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": { - "define-properties": "^1.1.3" + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -9368,186 +12491,192 @@ "url": "https://github.com/sponsors/ljharb" } }, - "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/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/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3" + "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/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" - }, - "engines": { - "node": ">=8.6" - } - }, - "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/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, "dependencies": { - "pump": "^3.0.0" + "ci-info": "^2.0.0" }, - "engines": { - "node": ">=6" + "bin": { + "is-ci": "bin.js" } }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "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/graphql": { - "version": "16.9.0", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.9.0.tgz", - "integrity": "sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==", + "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": { + "hasown": "^2.0.2" + }, "engines": { - "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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==", + "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": { - "tslib": "^2.1.0" + "is-typed-array": "^1.1.13" }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, - "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" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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==", + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, - "peerDependencies": { - "graphql": ">=0.11 <=16" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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": { - "ansi-red": "^0.1.1", - "coffee-script": "^1.12.4", - "extend-shallow": "^2.0.1", - "js-yaml": "^3.8.1", - "toml": "^2.3.2" + "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, + "bin": { + "is-docker": "cli.js" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "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": { - "is-extendable": "^0.1.0" + "is-plain-object": "^2.0.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==", + "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" } }, - "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", + "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": { - "concat-with-sourcemaps": "*", - "lodash.template": "^4.4.0", - "through2": "^2.0.0" + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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/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": ">=8" + } }, - "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==", + "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/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==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "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==", + "dependencies": { + "is-extglob": "^2.1.1" + }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "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/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": { - "es-define-property": "^1.0.0" + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + }, + "engines": { + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "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" @@ -9556,10 +12685,25 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "node_modules/is-nan": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", + "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", "dev": true, "engines": { "node": ">= 0.4" @@ -9568,13 +12712,33 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "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": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", "dev": true, "dependencies": { - "has-symbols": "^1.0.3" + "has-tostringtag": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -9583,448 +12747,442 @@ "url": "https://github.com/sponsors/ljharb" } }, - "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==", + "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": ">=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/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dependencies": { - "function-bind": "^1.1.2" + "isobject": "^3.0.1" }, "engines": { - "node": ">= 0.4" + "node": ">=0.10.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==", + "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/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" + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "engines": { + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/ljharb" } }, - "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==", + "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": { - "@types/hast": "^3.0.0" + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/ljharb" } }, - "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/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/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==", + "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": { - "react-is": "^16.7.0" + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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==", + "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": { - "parse-passwd": "^1.0.0" + "has-symbols": "^1.0.2" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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, + "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==", "dependencies": { - "whatwg-encoding": "^1.0.5" + "which-typed-array": "^1.1.14" }, "engines": { - "node": ">=10" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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==", + "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/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==", + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, "funding": { - "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" + "url": "https://github.com/sponsors/ljharb" } }, - "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==", + "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": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" + "call-bind": "^1.0.2" }, - "engines": { - "node": ">= 6" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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/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": { - "agent-base": "6", - "debug": "4" + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4" }, "engines": { - "node": ">= 6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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/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": ">=10.17.0" + "node": ">=0.10.0" } }, - "node_modules/husky": { - "version": "9.1.6", - "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.6.tgz", - "integrity": "sha512-sqbjZKK7kf44hfdE94EoX8MZNk0n7HeW37O4YrVGCF4wzgQjp+akPAkfUK5LZ6KuR/6sqeAVuXHji+RzQgOn5A==", + "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, - "bin": { - "husky": "bin.js" + "dependencies": { + "is-docker": "^2.0.0" }, "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/typicode" + "node": ">=8" } }, - "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/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==", + "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": ">=0.10.0" } }, - "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/isomorphic-timers-promises": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-timers-promises/-/isomorphic-timers-promises-1.0.1.tgz", + "integrity": "sha512-u4sej9B1LPSxTGKB/HiuzvEQnXH0ECYkSVQU39koSwmFAxhlEAFl9RdTvLv4TOTQUgBS5O3O5fwUxk6byBZ+IQ==", + "engines": { + "node": ">=10" } }, - "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": { - "cross-fetch": "4.0.0" + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "engines": { + "node": ">=8" } }, - "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, + "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": { - "safer-buffer": ">= 2.1.2 < 3.0.0" + "@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": ">=0.10.0" + "node": ">=8" } }, - "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==", + "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, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" + "bin": { + "semver": "bin/semver.js" } }, - "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/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, "dependencies": { - "harmony-reflect": "^1.4.6" + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=4" + "node": ">=10" } }, - "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==", + "node_modules/istanbul-lib-report/node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, - "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, "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==", + "node": ">=10" + }, "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/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/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": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" }, "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=10" } }, - "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/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": ">=4" + "node": ">=0.10.0" } }, - "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/istanbul-reports": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", "dev": true, "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "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, - "engines": { - "node": ">=0.8.19" + "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/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==", + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dev": true, - "engines": { - "node": ">=8" + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.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/jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", + "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", "dev": true, "dependencies": { - "once": "^1.3.0", - "wrappy": "1" + "@jest/core": "^27.5.1", + "import-local": "^3.0.2", + "jest-cli": "^27.5.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "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" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "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/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": { + "@jest/types": "^27.5.1", + "execa": "^5.0.0", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } }, - "node_modules/inquirer": { - "version": "8.2.6", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", - "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", + "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": { - "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" + "@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": ">=12.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/inquirer/node_modules/chalk": { + "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" @@ -10036,808 +13194,771 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "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": { - "restore-cursor": "^3.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "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/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": ">=8" - } - }, - "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/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": { - "es-errors": "^1.3.0", - "hasown": "^2.0.0", - "side-channel": "^1.0.4" + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" }, "engines": { - "node": ">= 0.4" - } - }, - "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/invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "dependencies": { - "loose-envify": "^1.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "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/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, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1" - }, "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/chalk/ansi-styles?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/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/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/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": { - "has-tostringtag": "^1.0.0" + "@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" }, - "engines": { - "node": ">= 0.4" + "bin": { + "jest": "bin/jest.js" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "dependencies": { - "has-bigints": "^1.0.1" + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "devOptional": true, - "dependencies": { - "binary-extensions": "^2.0.0" + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" }, - "engines": { - "node": ">=8" + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "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==", + "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": { - "call-bind": "^1.0.2", - "has-tostringtag": "^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/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==", + "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": { + "@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": ">= 0.4" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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, - "dependencies": { - "ci-info": "^2.0.0" + "peerDependencies": { + "ts-node": ">=9.0.0" }, - "bin": { - "is-ci": "bin.js" + "peerDependenciesMeta": { + "ts-node": { + "optional": true + } } }, - "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/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==", + "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": { - "hasown": "^2.0.2" + "@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": ">= 0.4" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "@babel/core": "^7.8.0" } }, - "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/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": { - "is-typed-array": "^1.1.13" + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" }, "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/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==", + "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": { - "has-tostringtag": "^1.0.0" + "babel-plugin-jest-hoist": "^27.5.1", + "babel-preset-current-node-syntax": "^1.0.0" }, "engines": { - "node": ">= 0.4" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "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==", + "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, - "bin": { - "is-docker": "cli.js" + "dependencies": { + "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/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/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": { - "is-plain-object": "^2.0.4" + "@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": ">=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==", - "devOptional": true, - "engines": { - "node": ">=0.10.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/is-finalizationregistry": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", - "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", + "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": { - "call-bind": "^1.0.2" + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" }, - "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==", - "engines": { - "node": ">=8" - } - }, - "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": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "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/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, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "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, + "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": { - "is-extglob": "^2.1.1" + "chalk": "^4.0.0", + "diff-sequences": "^26.6.2", + "jest-get-type": "^26.3.0", + "pretty-format": "^26.6.2" }, "engines": { - "node": ">=0.10.0" + "node": ">= 10.14.2" } }, - "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/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": { - "global-dirs": "^3.0.0", - "is-path-inside": "^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/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==", + "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": ">=8" + "node": ">= 10.14.2" } }, - "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/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, - "engines": { - "node": ">= 0.4" + "dependencies": { + "detect-newline": "^3.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "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/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": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "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==", + "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, - "engines": { - "node": ">=10" + "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" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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.12.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "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==", "dev": true, "dependencies": { - "has-tostringtag": "^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/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/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": { + "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/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/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": ">=8" - } - }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dependencies": { - "isobject": "^3.0.1" + "node": ">=10" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "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/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/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==", + "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": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "@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": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "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==", + "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": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "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/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": { - "call-bind": "^1.0.7" + "@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.4" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "optionalDependencies": { + "fsevents": "^2.3.2" } }, - "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==", + "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, - "engines": { - "node": ">=8" + "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" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "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/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": { - "has-tostringtag": "^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/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/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": { - "has-symbols": "^1.0.2" + "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/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/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, - "dependencies": { - "which-typed-array": "^1.1.14" - }, "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "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/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/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" + "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" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "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/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": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "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==", + "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.2" + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "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/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, - "dependencies": { - "call-bind": "^1.0.7", - "get-intrinsic": "^1.2.4" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=6.16.0" } }, - "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/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": { + "@jedmao/location": "^3.0.0", + "jest-diff": "^29.6.4" + }, "engines": { - "node": ">=0.10.0" + "node": "^16.10.0 || >=18.0.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==", + "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": { - "is-docker": "^2.0.0" + "@sinclair/typebox": "^0.27.8" }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "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==", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "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/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "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": { + "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/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/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": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.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/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": { - "@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" + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "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==", + "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, - "bin": { - "semver": "bin/semver.js" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "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==", + "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": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "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/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, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "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/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": { + "chalk": "^4.0.0", + "jest-diff": "^27.5.1", + "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/istanbul-reports": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "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": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^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/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==", + "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, - "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" + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest": { + "node_modules/jest-matcher-utils/node_modules/jest-diff": { "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", - "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", "dev": true, "dependencies": { - "@jest/core": "^27.5.1", - "import-local": "^3.0.2", - "jest-cli": "^27.5.1" - }, - "bin": { - "jest": "bin/jest.js" + "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" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } } }, - "node_modules/jest-changed-files": { + "node_modules/jest-matcher-utils/node_modules/pretty-format": { "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.5.1.tgz", - "integrity": "sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, "dependencies": { - "@jest/types": "^27.5.1", - "execa": "^5.0.0", - "throat": "^6.0.1" + "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-circus": { + "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/chalk/ansi-styles?sponsor=1" + } + }, + "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-circus/-/jest-circus-27.5.1.tgz", - "integrity": "sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", "dev": true, "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/test-result": "^27.5.1", + "@babel/code-frame": "^7.12.13", "@jest/types": "^27.5.1", - "@types/node": "*", + "@types/stack-utils": "^2.0.0", "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", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", "pretty-format": "^27.5.1", "slash": "^3.0.0", - "stack-utils": "^2.0.3", - "throat": "^6.0.1" + "stack-utils": "^2.0.3" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-circus/node_modules/chalk": { + "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==", @@ -10853,7 +13974,7 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-circus/node_modules/pretty-format": { + "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==", @@ -10867,7 +13988,7 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-circus/node_modules/pretty-format/node_modules/ansi-styles": { + "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==", @@ -10879,47 +14000,86 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-circus/node_modules/react-is": { + "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-cli": { + "node_modules/jest-mock": { "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", - "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", "dev": true, "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" + "@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==", + "dev": true, + "engines": { + "node": ">=6" }, "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + "jest-resolve": "*" }, "peerDependenciesMeta": { - "node-notifier": { + "jest-resolve": { "optional": true } } }, - "node_modules/jest-cli/node_modules/chalk": { + "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": { + "@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" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/jest-preview" + } + }, + "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" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", @@ -10935,103 +14095,99 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-config": { + "node_modules/jest-regex-util": { "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", - "integrity": "sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "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": { - "@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-haste-map": "^27.5.1", + "jest-pnp-resolver": "^1.2.2", "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" + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^3.0.0" }, "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_modules/jest-config/node_modules/babel-jest": { + "node_modules/jest-resolve-dependencies": { "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", - "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz", + "integrity": "sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==", "dev": 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" + "jest-regex-util": "^27.5.1", + "jest-snapshot": "^27.5.1" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" } }, - "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==", + "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/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.0.0", - "@types/babel__traverse": "^7.0.6" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-config/node_modules/babel-preset-jest": { + "node_modules/jest-runner": { "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz", - "integrity": "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.5.1.tgz", + "integrity": "sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==", "dev": true, "dependencies": { - "babel-plugin-jest-hoist": "^27.5.1", - "babel-preset-current-node-syntax": "^1.0.0" + "@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": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" } }, - "node_modules/jest-config/node_modules/chalk": { + "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==", @@ -11047,7 +14203,7 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-config/node_modules/jest-environment-node": { + "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==", @@ -11064,54 +14220,40 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-config/node_modules/pretty-format": { + "node_modules/jest-runtime": { "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/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/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==", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.5.1.tgz", + "integrity": "sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==", "dev": true, "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" + "@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.14.2" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-diff/node_modules/chalk": { + "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==", @@ -11127,53 +14269,53 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "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.14.2" - } - }, - "node_modules/jest-docblock": { + "node_modules/jest-serializer": { "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/jest-serializer/-/jest-serializer-27.5.1.tgz", + "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", "dev": true, "dependencies": { - "detect-newline": "^3.0.0" + "@types/node": "*", + "graceful-fs": "^4.2.9" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "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": ">=8" - } - }, - "node_modules/jest-each": { + "node_modules/jest-snapshot": { "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.5.1.tgz", - "integrity": "sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==", + "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": { + "@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", - "pretty-format": "^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-each/node_modules/chalk": { + "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==", @@ -11189,7 +14331,31 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-each/node_modules/pretty-format": { + "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": "^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==", + "dev": true, + "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==", @@ -11203,7 +14369,7 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-each/node_modules/pretty-format/node_modules/ansi-styles": { + "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==", @@ -11215,94 +14381,30 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-each/node_modules/react-is": { + "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/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": { - "@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": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "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.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.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==", - "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": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/jest-jasmine2": { + "node_modules/jest-util": { "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz", - "integrity": "sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", "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" + "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-jasmine2/node_modules/chalk": { + "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==", @@ -11318,64 +14420,52 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-jasmine2/node_modules/pretty-format": { + "node_modules/jest-validate": { "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", + "integrity": "sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==", "dev": true, "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" + "@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-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==", + "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" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "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/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/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": { - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "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": ">=10" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-leak-detector/node_modules/pretty-format": { + "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==", @@ -11389,53 +14479,43 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.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": ">=6.16.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/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, - "dependencies": { - "@jedmao/location": "^3.0.0", - "jest-diff": "^29.6.4" - }, "engines": { - "node": "^16.10.0 || >=18.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "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/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": { - "@sinclair/typebox": "^0.27.8" + "@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": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "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/jest-location-mock/node_modules/chalk": { + "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==", @@ -11451,2410 +14531,2470 @@ "url": "https://github.com/chalk/chalk?sponsor=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==", + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 10.13.0" } }, - "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/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": { - "chalk": "^4.0.0", - "diff-sequences": "^29.6.3", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" + "has-flag": "^4.0.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "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/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": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=14" } }, - "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/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/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": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "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": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=10" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } } }, - "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/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" + "node": ">=8.3.0" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } } }, - "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/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" + }, + "engines": { + "node": ">=6" + } + }, + "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 + }, + "node_modules/json2mq": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/json2mq/-/json2mq-0.2.0.tgz", + "integrity": "sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA==", + "license": "MIT", + "peer": true, + "dependencies": { + "string-convert": "^0.2.0" + } + }, + "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/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": { - "chalk": "^4.0.0", - "jest-diff": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=4.0" } }, - "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==", + "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": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "json-buffer": "3.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==", - "dev": true, + "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": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=0.10.0" } }, - "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/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "dev": true, - "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": ">=6" } }, - "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/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": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" + "package-json": "^6.3.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=8" } }, - "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" + "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" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "engines": { + "node": ">=0.10.0" } }, - "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, + "node_modules/lcov-result-merger": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/lcov-result-merger/-/lcov-result-merger-5.0.1.tgz", + "integrity": "sha512-i53RjTYfqbHgerqGtuJjDfARDU340zNxXrJudQZU3o8ak9rrx8FDQUKf38Cjm6MtbqonqiDFmoKuUe++uZbvOg==", "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" + "fast-glob": "^3.2.11", + "yargs": "^16.2.0" + }, + "bin": { + "lcov-result-merger": "bin/lcov-result-merger.js" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=14" } }, - "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/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, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=6" } }, - "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==", + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">= 0.8.0" } }, - "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/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", "dev": true, "engines": { "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "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/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/jest-mock": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", - "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "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": { + "uc.micro": "^2.0.0" + } + }, + "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": { - "@jest/types": "^27.5.1", - "@types/node": "*" + "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": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=18.12.0" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" } }, - "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==", + "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": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" + "node": "^12.17.0 || ^14.13 || >=16.0.0" }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "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/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": ">=18" + } + }, + "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, - "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" + "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" }, - "bin": { - "jest-preview": "cli/index.js" + "engines": { + "node": ">=16.17" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/jest-preview" + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "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/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": ">=10" + "node": ">=16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "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/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, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, "engines": { - "node": ">=10" + "node": ">=16.17.0" + } + }, + "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" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "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.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" } }, - "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==", + "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, - "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" - }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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/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": { - "@jest/types": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-snapshot": "^27.5.1" + "path-key": "^4.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "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": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "mimic-fn": "^4.0.0" }, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "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/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, - "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" - }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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/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": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "engines": { + "node": ">=14" }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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": ">=10" + "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "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, - "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" + "bin": { + "yaml": "bin.mjs" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">= 14" } }, - "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, + "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": { - "@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" + "expand-range": "^1.8.1", + "extend-shallow": "^2.0.1", + "is-number": "^2.1.0", + "repeat-string": "^1.5.2" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=0.10.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==", - "dev": true, + "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": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "is-extendable": "^0.1.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==", + "engines": { + "node": ">=0.10.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==", + "dependencies": { + "kind-of": "^3.0.2" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=0.10.0" } }, - "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, + "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": { - "@types/node": "*", - "graceful-fs": "^4.2.9" + "is-buffer": "^1.1.5" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=0.10.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==", + "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": { - "@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" + "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" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=18.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==", + "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, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/chalk/ansi-regex?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==", + "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.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "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==", + "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": { - "chalk": "^4.0.0", - "diff-sequences": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "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": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" + "ansi-regex": "^6.0.1" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "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==", + "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": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/chalk/wrap-ansi?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==", - "dev": true - }, - "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==", + "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, - "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": ">= 12.13.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==", + "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": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "p-locate": "^4.1.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "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, + "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-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "license": "MIT", + "peer": true + }, + "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 + }, + "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": { - "@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" + "lodash._reinterpolate": "^3.0.0", + "lodash.templatesettings": "^4.0.0" + } + }, + "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": { + "lodash._reinterpolate": "^3.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==", + "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": ">=10" + "node": ">=18" }, "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==", + "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": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "environment": "^1.0.0" }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "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, - "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": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "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==", + "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" + "node": ">=12" }, "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/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/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": { - "@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==", + "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": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "get-east-asian-width": "^1.0.0" }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "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": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" }, "engines": { - "node": ">= 10.13.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "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==", + "node_modules/log-update/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": { - "has-flag": "^4.0.0" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "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": ">=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" + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "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": { - "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" + "ansi-regex": "^6.0.1" }, "engines": { - "node": ">=10" - }, - "peerDependencies": { - "canvas": "^2.5.0" + "node": ">=12" }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "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==", + "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, - "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": "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" + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=6" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "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/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/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/loupe": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.2.tgz", + "integrity": "sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==", + "dev": true, + "license": "MIT" }, - "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/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/json-stable-stringify-without-jsonify": { + "node_modules/lowercase-keys": { "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==", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", "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" - }, "engines": { - "node": ">=6" + "node": ">=0.10.0" } }, - "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==", + "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/lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==" + }, + "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, + "peer": true, + "bin": { + "lz-string": "bin/bin.js" + } + }, + "node_modules/magic-string": { + "version": "0.30.13", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.13.tgz", + "integrity": "sha512-8rYBO+MsWkgjDSOvLomYnzhdwEG51olQ4zL5KXnNJWV5MNmrb4rTZdrtkhxjnD/QyZUqR/Z/XDsUs/4ej2nx0g==", "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" + "@jridgewell/sourcemap-codec": "^1.5.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==", + "node_modules/magicast": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz", + "integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==", "dev": true, "dependencies": { - "json-buffer": "3.0.0" + "@babel/parser": "^7.25.4", + "@babel/types": "^7.25.4", + "source-map-js": "^1.2.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==", + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "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, - "engines": { - "node": ">=6" + "bin": { + "semver": "bin/semver.js" } }, - "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==", + "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": { - "package-json": "^6.3.0" + "tmpl": "1.0.5" + } + }, + "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": { + "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": ">=8" + "node": ">=0.10.0" } }, - "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==", + "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": { - "set-getter": "^0.1.0" + "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/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, - "engines": { - "node": ">=6" + "node_modules/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/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" } }, - "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, + "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": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" + "@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": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "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/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/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-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "engines": { - "node": ">= 0.8.0" + "node": ">= 8" } }, - "node_modules/lilconfig": { + "node_modules/micromark-util-character": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", - "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", - "dev": true, - "engines": { - "node": ">=10" + "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": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.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/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/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==", + "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": { - "uc.micro": "^2.0.0" + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" } }, - "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, + "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/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/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dependencies": { - "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" + "braces": "^3.0.3", + "picomatch": "^2.3.1" }, "engines": { - "node": ">=18.12.0" - }, - "funding": { - "url": "https://opencollective.com/lint-staged" + "node": ">=8.6" } }, - "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": "^12.17.0 || ^14.13 || >=16.0.0" + "node_modules/miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dependencies": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "bin": { + "miller-rabin": "bin/miller-rabin" } }, - "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/miller-rabin/node_modules/bn.js": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==" + }, + "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": ">=18" + "node": ">= 0.6" } }, - "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/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": { - "cross-spawn": "^7.0.3", - "get-stream": "^8.0.1", - "human-signals": "^5.0.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^4.1.0", - "strip-final-newline": "^3.0.0" - }, - "engines": { - "node": ">=16.17" + "mime-db": "1.52.0" }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "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": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 0.6" } }, - "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==", + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true, "engines": { - "node": ">=16.17.0" + "node": ">=6" } }, - "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==", + "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, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "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": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antonk52" + "node": ">=4" } }, - "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/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": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=4" } }, - "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/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/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" + }, + "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": { - "path-key": "^4.0.0" + "brace-expansion": "^1.1.7" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "*" } }, - "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": { - "mimic-fn": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, + "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/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "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/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "dev": true, "engines": { - "node": ">=12" + "node": ">=16 || 14 >=14.17" + } + }, + "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" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=0.10.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/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": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=10" } }, - "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, + "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/mute-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", + "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", + "license": "ISC", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^14.17.0 || ^16.13.0 || >=18.0.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, + "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": { - "yaml": "bin.mjs" + "nanoid": "bin/nanoid.cjs" }, "engines": { - "node": ">= 14" + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "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/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": { - "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" + "lower-case": "^2.0.2", + "tslib": "^2.0.3" } }, - "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/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "optional": true + }, + "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-extendable": "^0.1.0" + "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/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": ">=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/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/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": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" } }, - "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/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": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" + "html-entities": "^2.3.2" } }, - "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" + "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/node-stdlib-browser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/node-stdlib-browser/-/node-stdlib-browser-1.2.1.tgz", + "integrity": "sha512-dZezG3D88Lg22DwyjsDuUs7cCT/XGr8WwJgg/S3ZnkcWuPet2Tt/W1d2Eytb1Z73JpZv+XVCDI5TWv6UMRq0Gg==", + "dependencies": { + "assert": "^2.0.0", + "browser-resolve": "^2.0.0", + "browserify-zlib": "^0.2.0", + "buffer": "^5.7.1", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "create-require": "^1.1.1", + "crypto-browserify": "^3.11.0", + "domain-browser": "^4.22.0", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "isomorphic-timers-promises": "^1.0.1", + "os-browserify": "^0.3.0", + "path-browserify": "^1.0.1", + "pkg-dir": "^5.0.0", + "process": "^0.11.10", + "punycode": "^1.4.1", + "querystring-es3": "^0.2.1", + "readable-stream": "^3.6.0", + "stream-browserify": "^3.0.0", + "stream-http": "^3.2.0", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.1", + "url": "^0.11.4", + "util": "^0.12.4", + "vm-browserify": "^1.0.1" }, "engines": { - "node": ">=18.0.0" + "node": ">=10" } }, - "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": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "node_modules/node-stdlib-browser/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" } }, - "node_modules/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, + "node_modules/node-stdlib-browser/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": ">=12" + "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "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": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" + "node_modules/node-stdlib-browser/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": ">=18" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "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/node-stdlib-browser/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": { - "ansi-regex": "^6.0.1" + "yocto-queue": "^0.1.0" }, "engines": { - "node": ">=12" + "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "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/node-stdlib-browser/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": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" + "p-limit": "^3.0.2" }, "engines": { - "node": ">=18" + "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "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": ">= 12.13.0" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/locate-path": { + "node_modules/node-stdlib-browser/node_modules/pkg-dir": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz", + "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==", "dependencies": { - "p-locate": "^4.1.0" + "find-up": "^5.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" } }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "node_modules/node-stdlib-browser/node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==" }, - "node_modules/lodash._reinterpolate": { + "node_modules/normalize-path": { "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==", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "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/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": { - "lodash._reinterpolate": "^3.0.0" + "engines": { + "node": ">=0.10.0" } }, - "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/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": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" + "path-key": "^3.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, - "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": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "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/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": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=0.10.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": ">=18" - }, + "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==", "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "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, + "node_modules/object-is": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", "dependencies": { - "environment": "^1.0.0" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" }, "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/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, + "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": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "node": ">= 0.4" } }, - "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, + "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==", + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, "engines": { - "node": ">=12" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "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/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==", + "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": { - "get-east-asian-width": "^1.0.0" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 0.4" } }, - "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/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": { - "ansi-styles": "^6.2.1", - "is-fullwidth-code-point": "^5.0.0" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" }, "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.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "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": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" }, "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 0.4" } }, - "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, + "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": { - "ansi-regex": "^6.0.1" + "isobject": "^3.0.1" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "node": ">=0.10.0" } }, - "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==", + "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": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "engines": { - "node": ">=18" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "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==", + "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": { - "js-tokens": "^3.0.0 || ^4.0.0" + "ee-first": "1.1.1" }, - "bin": { - "loose-envify": "cli.js" + "engines": { + "node": ">= 0.8" } }, - "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/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": { - "tslib": "^2.0.3" + "wrappy": "1" } }, - "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==", + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "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": { - "yallist": "^3.0.2" - } - }, - "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/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, - "peer": true, - "bin": { - "lz-string": "bin/bin.js" + "regex": "^4.3.2" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" } }, - "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/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": { - "semver": "^6.0.0" + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" }, "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" + "node_modules/optimism": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/optimism/-/optimism-0.18.0.tgz", + "integrity": "sha512-tGn8+REwLRNFnb9WmcY5IfpOqeX2kpaYJ1s6Ae3mn12AeydLkR3j+jSCmVQFoXqU8D41PAJ1RG1rCRNWmNZVmQ==", + "dependencies": { + "@wry/caches": "^1.0.0", + "@wry/context": "^0.7.0", + "@wry/trie": "^0.4.3", + "tslib": "^2.3.0" } }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, + "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": { - "tmpl": "1.0.5" + "tslib": "^2.3.0" + }, + "engines": { + "node": ">=8" } }, - "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==", + "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, "dependencies": { - "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" + "@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" }, - "bin": { - "markdown-it": "bin/markdown-it.mjs" + "engines": { + "node": ">= 0.8.0" } }, - "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/os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==" }, - "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/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "license": "MIT", "engines": { "node": ">=0.10.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/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": { - "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" + "p-try": "^2.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "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": { - "@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" + "p-limit": "^2.2.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=8" } }, - "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/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/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/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/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": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "engines": { + "node": ">=8" + } }, - "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/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", "dev": true }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "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, - "engines": { - "node": ">= 8" + "bin": { + "semver": "bin/semver.js" } }, - "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" - } - ], + "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": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" } }, - "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/parse-asn1": { + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.7.tgz", + "integrity": "sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==", + "dependencies": { + "asn1.js": "^4.10.1", + "browserify-aes": "^1.2.0", + "evp_bytestokey": "^1.0.3", + "hash-base": "~3.0", + "pbkdf2": "^3.1.2", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } }, - "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" - } - ], + "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": { - "micromark-util-character": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-symbol": "^2.0.0" + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/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/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/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/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/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "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, - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, "engines": { - "node": ">=8.6" + "node": ">= 0.8" } }, - "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, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==" + }, + "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": ">= 0.6" + "node": ">=8" } }, - "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/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, - "dependencies": { - "mime-db": "1.52.0" - }, "engines": { - "node": ">= 0.6" + "node": ">=0.10.0" } }, - "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/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": ">=6" + "node": ">=8" } }, - "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==", + "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-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, "engines": { - "node": ">=18" + "node": ">=16 || 14 >=14.18" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/isaacs" } }, - "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, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "engines": { - "node": ">=4" + "node": ">=8" } }, - "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==", + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", + "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=4" + "node": ">= 14.16" } }, - "node_modules/minimatch": { + "node_modules/pbkdf2": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", "dependencies": { - "brace-expansion": "^1.1.7" + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" }, "engines": { - "node": "*" + "node": ">=0.12" } }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "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==", + "license": "MIT", + "peer": true + }, + "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==", + "engines": { + "node": ">=8.6" + }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "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" + "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": ">=0.10" + } + }, + "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/mrmime": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", - "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==", + "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": ">=10" + "node": ">= 6" } }, - "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/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } }, - "node_modules/mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" + "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/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "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" } ], - "bin": { - "nanoid": "bin/nanoid.cjs" + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.1", + "source-map-js": "^1.2.0" }, "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "node": "^10 || ^12 || >=14" } }, - "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==", + "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": { - "lower-case": "^2.0.2", - "tslib": "^2.0.3" - } - }, - "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": { - "whatwg-url": "^5.0.0" + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" }, "engines": { - "node": "4.x || >=6.0.0" + "node": ">=10.0.0" }, "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "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==", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "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": { - "html-entities": "^2.3.2" - } - }, - "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.10.0" + "postcss": "^8.0.0" } }, - "node_modules/npm-run-path": { + "node_modules/postcss-load-config": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz", + "integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==", "dev": true, "dependencies": { - "path-key": "^3.0.0" + "lilconfig": "^2.0.5", + "yaml": "^2.1.1" }, "engines": { - "node": ">=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/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/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, + "node": ">= 14" + }, "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" + "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/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/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, - "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 14" } }, - "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==", + "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": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" + "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": ">= 0.4" + "peerDependencies": { + "postcss": "^8.0.0" } }, - "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==", + "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, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" - }, "engines": { - "node": ">= 0.4" + "node": "^10 || ^12 || >= 14" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "postcss": "^8.1.0" } }, - "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==", + "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": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2" + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" }, "engines": { - "node": ">= 0.4" + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" } }, - "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==", + "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": { - "isobject": "^3.0.1" + "postcss-selector-parser": "^6.0.4" }, "engines": { - "node": ">=0.10.0" + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" } }, - "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==", + "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-object-atoms": "^1.0.0" + "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/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/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": { - "ee-first": "1.1.1" + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" }, "engines": { - "node": ">= 0.8" + "node": ">=4" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } + "node_modules/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/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dependencies": { - "mimic-fn": "^2.1.0" - }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 0.8.0" } }, - "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": { - "regex": "^4.3.2" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" + "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/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": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" + "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": ">=12" + "node": ">=14" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optimism": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/optimism/-/optimism-0.18.0.tgz", - "integrity": "sha512-tGn8+REwLRNFnb9WmcY5IfpOqeX2kpaYJ1s6Ae3mn12AeydLkR3j+jSCmVQFoXqU8D41PAJ1RG1rCRNWmNZVmQ==", - "dependencies": { - "@wry/caches": "^1.0.0", - "@wry/context": "^0.7.0", - "@wry/trie": "^0.4.3", - "tslib": "^2.3.0" + "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "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==", + "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": { - "tslib": "^2.3.0" + "fast-diff": "^1.1.2" }, "engines": { - "node": ">=8" + "node": ">=6.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/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, - "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" + "@jest/types": "^26.6.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^17.0.1" }, "engines": { - "node": ">= 0.8.0" + "node": ">= 10" } }, - "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==", + "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": { - "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" + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 10.14.2" + } + }, + "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/ora/node_modules/chalk": { + "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" @@ -13866,725 +17006,1000 @@ "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==", - "dependencies": { - "restore-cursor": "^3.1.0" - }, + "node_modules/pretty-format/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", "engines": { - "node": ">=8" + "node": ">= 0.6.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==", + "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": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" }, "engines": { - "node": ">=8" - } - }, - "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": ">= 6" } }, - "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/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/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, + "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": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" + "react-is": "^16.3.2", + "warning": "^4.0.0" }, + "peerDependencies": { + "react": ">=0.14.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/sponsors/sindresorhus" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "node_modules/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/public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dependencies": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/public-encrypt/node_modules/bn.js": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==" + }, + "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": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" + "end-of-stream": "^1.1.0", + "once": "^1.3.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/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": ">=6" } }, - "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": { - "got": "^9.6.0", - "registry-auth-token": "^4.0.0", - "registry-url": "^5.0.0", - "semver": "^6.2.0" - }, + "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": ">=8" + "node": ">=6" } }, - "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/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, - "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/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" + "escape-goat": "^2.0.0" }, "engines": { - "node": ">=6" + "node": ">=8" } }, - "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/qs": { + "version": "6.13.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.1.tgz", + "integrity": "sha512-EJPeIn0CYrGu+hli1xilKAPXODtJ12T0sP63Ijx2/khC2JtuaN3JyNIpvmnkmaEtha9ocbG4A4cMcr+TvqvwQg==", "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" + "side-channel": "^1.0.6" }, "engines": { - "node": ">=8" + "node": ">=0.6" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "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, + "node_modules/querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==", "engines": { - "node": ">=0.10.0" + "node": ">=0.4.x" } }, - "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/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } + "node_modules/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/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" + "node_modules/raf": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", + "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "license": "MIT", + "peer": true, + "dependencies": { + "performance-now": "^2.1.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": ">=0.10.0" - } + "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/path-key": { + "node_modules/randomatic": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, + "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": ">=8" + "node": ">= 0.10.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": { + "node_modules/randomatic/node_modules/is-number": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "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/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dependencies": { + "safe-buffer": "^5.1.0" + } }, - "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": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "node_modules/randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dependencies": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.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==", + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "dev": true, - "bin": { - "pidtree": "bin/pidtree.js" + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" }, - "engines": { - "node": ">=0.10" + "bin": { + "rc": "cli.js" } }, - "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/rc-align": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/rc-align/-/rc-align-2.4.5.tgz", + "integrity": "sha512-nv9wYUYdfyfK+qskThf4BQUSIadeI/dCsfaMZfNEoxm9HwOIioQ+LyqmMK6jWHAZQgOzMLaqawhuBXlF63vgjw==", + "license": "MIT", + "peer": true, + "dependencies": { + "babel-runtime": "^6.26.0", + "dom-align": "^1.7.0", + "prop-types": "^15.5.8", + "rc-util": "^4.0.4" } }, - "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/rc-align/node_modules/rc-util": { + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-4.21.1.tgz", + "integrity": "sha512-Z+vlkSQVc1l8O2UjR3WQ+XdWlhj5q9BMQNLk2iOBch75CqPfrJyGtcWMcnhRlNuDu0Ndtt4kLVO8JI8BrABobg==", + "license": "MIT", + "peer": true, + "dependencies": { + "add-dom-event-listener": "^1.1.0", + "prop-types": "^15.5.10", + "react-is": "^16.12.0", + "react-lifecycles-compat": "^3.0.4", + "shallowequal": "^1.1.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==", - "dev": true, + "node_modules/rc-align/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==", + "license": "MIT", + "peer": true + }, + "node_modules/rc-animate": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/rc-animate/-/rc-animate-2.11.1.tgz", + "integrity": "sha512-1NyuCGFJG/0Y+9RKh5y/i/AalUCA51opyyS/jO2seELpgymZm2u9QV3xwODwEuzkmeQ1BDPxMLmYLcTJedPlkQ==", + "license": "MIT", + "peer": true, "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" + "babel-runtime": "6.x", + "classnames": "^2.2.6", + "css-animation": "^1.3.2", + "prop-types": "15.x", + "raf": "^3.4.0", + "rc-util": "^4.15.3", + "react-lifecycles-compat": "^3.0.4" } }, - "node_modules/possible-typed-array-names": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", - "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", - "dev": true, - "engines": { - "node": ">= 0.4" + "node_modules/rc-animate/node_modules/rc-util": { + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-4.21.1.tgz", + "integrity": "sha512-Z+vlkSQVc1l8O2UjR3WQ+XdWlhj5q9BMQNLk2iOBch75CqPfrJyGtcWMcnhRlNuDu0Ndtt4kLVO8JI8BrABobg==", + "license": "MIT", + "peer": true, + "dependencies": { + "add-dom-event-listener": "^1.1.0", + "prop-types": "^15.5.10", + "react-is": "^16.12.0", + "react-lifecycles-compat": "^3.0.4", + "shallowequal": "^1.1.0" } }, - "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" - } - ], + "node_modules/rc-animate/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==", + "license": "MIT", + "peer": true + }, + "node_modules/rc-cascader": { + "version": "3.30.0", + "resolved": "https://registry.npmjs.org/rc-cascader/-/rc-cascader-3.30.0.tgz", + "integrity": "sha512-rrzSbk1Bdqbu+pDwiLCLHu72+lwX9BZ28+JKzoi0DWZ4N29QYFeip8Gctl33QVd2Xg3Rf14D3yAOG76ElJw16w==", + "license": "MIT", + "peer": true, "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.1", - "source-map-js": "^1.2.0" + "@babel/runtime": "^7.25.7", + "classnames": "^2.3.1", + "rc-select": "~14.16.2", + "rc-tree": "~5.10.1", + "rc-util": "^5.43.0" }, - "engines": { - "node": "^10 || ^12 || >=14" + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.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==", - "dev": true, + "node_modules/rc-checkbox": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/rc-checkbox/-/rc-checkbox-3.3.0.tgz", + "integrity": "sha512-Ih3ZaAcoAiFKJjifzwsGiT/f/quIkxJoklW4yKGho14Olulwn8gN7hOBve0/WGDg5o/l/5mL0w7ff7/YGvefVw==", + "license": "MIT", + "peer": true, "dependencies": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - }, - "engines": { - "node": ">=10.0.0" + "@babel/runtime": "^7.10.1", + "classnames": "^2.3.2", + "rc-util": "^5.25.2" }, "peerDependencies": { - "postcss": "^8.0.0" + "react": ">=16.9.0", + "react-dom": ">=16.9.0" } }, - "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, + "node_modules/rc-collapse": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/rc-collapse/-/rc-collapse-3.9.0.tgz", + "integrity": "sha512-swDdz4QZ4dFTo4RAUMLL50qP0EY62N2kvmk2We5xYdRwcRn8WcYtuetCJpwpaCbUfUt5+huLpVxhvmnK+PHrkA==", + "license": "MIT", + "peer": true, "dependencies": { - "lilconfig": "^2.0.5", - "yaml": "^2.1.1" + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-motion": "^2.3.4", + "rc-util": "^5.27.0" }, - "engines": { - "node": ">= 14" + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-dialog": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/rc-dialog/-/rc-dialog-9.6.0.tgz", + "integrity": "sha512-ApoVi9Z8PaCQg6FsUzS8yvBEQy0ZL2PkuvAgrmohPkN3okps5WZ5WQWPc1RNuiOKaAYv8B97ACdsFU5LizzCqg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.10.1", + "@rc-component/portal": "^1.0.0-8", + "classnames": "^2.2.6", + "rc-motion": "^2.3.0", + "rc-util": "^5.21.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-drawer": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/rc-drawer/-/rc-drawer-7.2.0.tgz", + "integrity": "sha512-9lOQ7kBekEJRdEpScHvtmEtXnAsy+NGDXiRWc2ZVC7QXAazNVbeT4EraQKYwCME8BJLa8Bxqxvs5swwyOepRwg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.23.9", + "@rc-component/portal": "^1.1.1", + "classnames": "^2.2.6", + "rc-motion": "^2.6.1", + "rc-util": "^5.38.1" }, "peerDependencies": { - "postcss": ">=8.0.9", - "ts-node": ">=9.0.0" + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-dropdown": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/rc-dropdown/-/rc-dropdown-4.2.1.tgz", + "integrity": "sha512-YDAlXsPv3I1n42dv1JpdM7wJ+gSUBfeyPK59ZpBD9jQhK9jVuxpjj3NmWQHOBceA1zEPVX84T2wbdb2SD0UjmA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.18.3", + "@rc-component/trigger": "^2.0.0", + "classnames": "^2.2.6", + "rc-util": "^5.44.1" }, - "peerDependenciesMeta": { - "postcss": { - "optional": true - }, - "ts-node": { - "optional": true - } + "peerDependencies": { + "react": ">=16.11.0", + "react-dom": ">=16.11.0" } }, - "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, + "node_modules/rc-field-form": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/rc-field-form/-/rc-field-form-2.7.0.tgz", + "integrity": "sha512-hgKsCay2taxzVnBPZl+1n4ZondsV78G++XVsMIJCAoioMjlMQR9YwAp7JZDIECzIu2Z66R+f4SFIRrO2DjDNAA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.18.0", + "@rc-component/async-validator": "^5.0.3", + "rc-util": "^5.32.2" + }, "engines": { - "node": ">= 14" + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" } }, - "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, + "node_modules/rc-image": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/rc-image/-/rc-image-7.11.0.tgz", + "integrity": "sha512-aZkTEZXqeqfPZtnSdNUnKQA0N/3MbgR7nUnZ+/4MfSFWPFHZau4p5r5ShaI0KPEMnNjv4kijSCFq/9wtJpwykw==", + "license": "MIT", + "peer": 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" + "@babel/runtime": "^7.11.2", + "@rc-component/portal": "^1.0.2", + "classnames": "^2.2.6", + "rc-dialog": "~9.6.0", + "rc-motion": "^2.6.2", + "rc-util": "^5.34.1" }, "peerDependencies": { - "postcss": "^8.0.0" + "react": ">=16.9.0", + "react-dom": ">=16.9.0" } }, - "node_modules/postcss-modules-extract-imports": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", - "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", - "dev": true, - "engines": { - "node": "^10 || ^12 || >= 14" + "node_modules/rc-input": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/rc-input/-/rc-input-1.6.4.tgz", + "integrity": "sha512-lBZhfRD4NSAUW0zOKLUeI6GJuXkxeZYi0hr8VcJgJpyTNOvHw1ysrKWAHcEOAAHj7guxgmWYSi6xWrEdfrSAsA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "rc-util": "^5.18.1" }, "peerDependencies": { - "postcss": "^8.1.0" + "react": ">=16.0.0", + "react-dom": ">=16.0.0" } }, - "node_modules/postcss-modules-local-by-default": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz", - "integrity": "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==", - "dev": true, + "node_modules/rc-input-number": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/rc-input-number/-/rc-input-number-9.3.0.tgz", + "integrity": "sha512-JQ363ywqRyxwgVxpg2z2kja3CehTpYdqR7emJ/6yJjRdbvo+RvfE83fcpBCIJRq3zLp8SakmEXq60qzWyZ7Usw==", + "license": "MIT", + "peer": true, "dependencies": { - "icss-utils": "^5.0.0", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.1.0" + "@babel/runtime": "^7.10.1", + "@rc-component/mini-decimal": "^1.0.1", + "classnames": "^2.2.5", + "rc-input": "~1.6.0", + "rc-util": "^5.40.1" }, - "engines": { - "node": "^10 || ^12 || >= 14" + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-mentions": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/rc-mentions/-/rc-mentions-2.17.0.tgz", + "integrity": "sha512-sfHy+qLvc+p8jx8GUsujZWXDOIlIimp6YQz7N5ONQ6bHsa2kyG+BLa5k2wuxgebBbH97is33wxiyq5UkiXRpHA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.22.5", + "@rc-component/trigger": "^2.0.0", + "classnames": "^2.2.6", + "rc-input": "~1.6.0", + "rc-menu": "~9.16.0", + "rc-textarea": "~1.8.0", + "rc-util": "^5.34.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-menu": { + "version": "9.16.0", + "resolved": "https://registry.npmjs.org/rc-menu/-/rc-menu-9.16.0.tgz", + "integrity": "sha512-vAL0yqPkmXWk3+YKRkmIR8TYj3RVdEt3ptG2jCJXWNAvQbT0VJJdRyHZ7kG/l1JsZlB+VJq/VcYOo69VR4oD+w==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.10.1", + "@rc-component/trigger": "^2.0.0", + "classnames": "2.x", + "rc-motion": "^2.4.3", + "rc-overflow": "^1.3.1", + "rc-util": "^5.27.0" }, "peerDependencies": { - "postcss": "^8.1.0" + "react": ">=16.9.0", + "react-dom": ">=16.9.0" } }, - "node_modules/postcss-modules-scope": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz", - "integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==", - "dev": true, + "node_modules/rc-motion": { + "version": "2.9.5", + "resolved": "https://registry.npmjs.org/rc-motion/-/rc-motion-2.9.5.tgz", + "integrity": "sha512-w+XTUrfh7ArbYEd2582uDrEhmBHwK1ZENJiSJVb7uRxdE7qJSYjbO2eksRXmndqyKqKoYPc9ClpPh5242mV1vA==", + "license": "MIT", + "peer": true, "dependencies": { - "postcss-selector-parser": "^6.0.4" - }, - "engines": { - "node": "^10 || ^12 || >= 14" + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "rc-util": "^5.44.0" }, "peerDependencies": { - "postcss": "^8.1.0" + "react": ">=16.9.0", + "react-dom": ">=16.9.0" } }, - "node_modules/postcss-modules-values": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", - "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", - "dev": true, + "node_modules/rc-notification": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/rc-notification/-/rc-notification-5.6.2.tgz", + "integrity": "sha512-Id4IYMoii3zzrG0lB0gD6dPgJx4Iu95Xu0BQrhHIbp7ZnAZbLqdqQ73aIWH0d0UFcElxwaKjnzNovTjo7kXz7g==", + "license": "MIT", + "peer": true, "dependencies": { - "icss-utils": "^5.0.0" + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-motion": "^2.9.0", + "rc-util": "^5.20.1" }, "engines": { - "node": "^10 || ^12 || >= 14" + "node": ">=8.x" }, "peerDependencies": { - "postcss": "^8.1.0" + "react": ">=16.9.0", + "react-dom": ">=16.9.0" } }, - "node_modules/postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", - "dev": true, + "node_modules/rc-overflow": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/rc-overflow/-/rc-overflow-1.3.2.tgz", + "integrity": "sha512-nsUm78jkYAoPygDAcGZeC2VwIg/IBGSodtOY3pMof4W3M9qRJgqaDYm03ZayHlde3I6ipliAxbN0RUcGf5KOzw==", + "license": "MIT", + "peer": true, "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.37.0" }, - "engines": { - "node": ">=4" + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" } }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, + "node_modules/rc-pagination": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-5.0.0.tgz", + "integrity": "sha512-QjrPvbAQwps93iluvFM62AEYglGYhWW2q/nliQqmvkTi4PXP4HHoh00iC1Sa5LLVmtWQHmG73fBi2x6H6vFHRg==", + "license": "MIT", "peer": true, - "engines": { - "node": ">= 0.8.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" + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.3.2", + "rc-util": "^5.38.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" } }, - "node_modules/prettier": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz", - "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==", - "bin": { - "prettier": "bin/prettier.cjs" + "node_modules/rc-picker": { + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/rc-picker/-/rc-picker-4.8.3.tgz", + "integrity": "sha512-hJ45qoEs4mfxXPAJdp1n3sKwADul874Cd0/HwnsEOE60H+tgiJUGgbOD62As3EG/rFVNS5AWRfBCDJJfmRqOVQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.24.7", + "@rc-component/trigger": "^2.0.0", + "classnames": "^2.2.1", + "rc-overflow": "^1.3.2", + "rc-resize-observer": "^1.4.0", + "rc-util": "^5.43.0" }, "engines": { - "node": ">=14" + "node": ">=8.x" }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" + "peerDependencies": { + "date-fns": ">= 2.x", + "dayjs": ">= 1.x", + "luxon": ">= 3.x", + "moment": ">= 2.x", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + }, + "peerDependenciesMeta": { + "date-fns": { + "optional": true + }, + "dayjs": { + "optional": true + }, + "luxon": { + "optional": true + }, + "moment": { + "optional": true + } } }, - "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, + "node_modules/rc-progress": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/rc-progress/-/rc-progress-4.0.0.tgz", + "integrity": "sha512-oofVMMafOCokIUIBnZLNcOZFsABaUw8PPrf1/y0ZBvKZNpOiu5h4AO9vv11Sw0p4Hb3D0yGWuEattcQGtNJ/aw==", + "license": "MIT", + "peer": true, "dependencies": { - "fast-diff": "^1.1.2" + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.6", + "rc-util": "^5.16.1" }, - "engines": { - "node": ">=6.0.0" + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" } }, - "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, + "node_modules/rc-rate": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/rc-rate/-/rc-rate-2.13.0.tgz", + "integrity": "sha512-oxvx1Q5k5wD30sjN5tqAyWTvJfLNNJn7Oq3IeS4HxWfAiC4BOXMITNAsw7u/fzdtO4MS8Ki8uRLOzcnEuoQiAw==", + "license": "MIT", + "peer": true, "dependencies": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.5", + "rc-util": "^5.0.1" }, "engines": { - "node": ">= 10" + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" } }, - "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/rc-resize-observer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/rc-resize-observer/-/rc-resize-observer-1.4.3.tgz", + "integrity": "sha512-YZLjUbyIWox8E9i9C3Tm7ia+W7euPItNWSPX5sCcQTYbnwDb5uNpnLHQCG1f22oZWUhLw4Mv2tFmeWe68CDQRQ==", + "license": "MIT", + "peer": true, "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" + "@babel/runtime": "^7.20.7", + "classnames": "^2.2.1", + "rc-util": "^5.44.1", + "resize-observer-polyfill": "^1.5.1" }, - "engines": { - "node": ">= 10.14.2" + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.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/rc-segmented": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/rc-segmented/-/rc-segmented-2.5.0.tgz", + "integrity": "sha512-B28Fe3J9iUFOhFJET3RoXAPFJ2u47QvLSYcZWC4tFYNGPEjug5LAxEasZlA/PpAxhdOPqGWsGbSj7ftneukJnw==", + "license": "MIT", + "peer": true, "dependencies": { - "@types/yargs-parser": "*" + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "rc-motion": "^2.4.4", + "rc-util": "^5.17.0" + }, + "peerDependencies": { + "react": ">=16.0.0", + "react-dom": ">=16.0.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/rc-select": { + "version": "14.16.4", + "resolved": "https://registry.npmjs.org/rc-select/-/rc-select-14.16.4.tgz", + "integrity": "sha512-jP6qf7+vjnxGvPpfPWbGYfFlSl3h8L2XcD4O7g2GYXmEeBC0mw+nPD7i++OOE8v3YGqP8xtYjRKAWCMLfjgxlw==", + "license": "MIT", + "peer": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@babel/runtime": "^7.10.1", + "@rc-component/trigger": "^2.1.1", + "classnames": "2.x", + "rc-motion": "^2.0.1", + "rc-overflow": "^1.3.1", + "rc-util": "^5.16.1", + "rc-virtual-list": "^3.5.2" }, "engines": { - "node": ">=10" + "node": ">=8.x" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "peerDependencies": { + "react": "*", + "react-dom": "*" } }, - "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, + "node_modules/rc-slider": { + "version": "11.1.7", + "resolved": "https://registry.npmjs.org/rc-slider/-/rc-slider-11.1.7.tgz", + "integrity": "sha512-ytYbZei81TX7otdC0QvoYD72XSlxvTihNth5OeZ6PMXyEDq/vHdWFulQmfDGyXK1NwKwSlKgpvINOa88uT5g2A==", + "license": "MIT", + "peer": true, "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.5", + "rc-util": "^5.36.0" }, "engines": { - "node": ">= 6" + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.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==", + "node_modules/rc-steps": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/rc-steps/-/rc-steps-6.0.1.tgz", + "integrity": "sha512-lKHL+Sny0SeHkQKKDJlAjV5oZ8DwCdS2hFhAkIjuQt1/pB81M0cA0ErVFdHq9+jmPmFw1vJB2F5NBzFXLJxV+g==", + "license": "MIT", + "peer": true, "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" + "@babel/runtime": "^7.16.7", + "classnames": "^2.2.3", + "rc-util": "^5.16.1" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" } }, - "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/rc-switch": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/rc-switch/-/rc-switch-4.1.0.tgz", + "integrity": "sha512-TI8ufP2Az9oEbvyCeVE4+90PDSljGyuwix3fV58p7HV2o4wBnVToEyomJRVyTaZeqNPAp+vqeo4Wnj5u0ZZQBg==", + "license": "MIT", + "peer": true, "dependencies": { - "react-is": "^16.3.2", - "warning": "^4.0.0" + "@babel/runtime": "^7.21.0", + "classnames": "^2.2.1", + "rc-util": "^5.30.0" }, "peerDependencies": { - "react": ">=0.14.0" + "react": ">=16.9.0", + "react-dom": ">=16.9.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": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/rc-table": { + "version": "7.49.0", + "resolved": "https://registry.npmjs.org/rc-table/-/rc-table-7.49.0.tgz", + "integrity": "sha512-/FoPLX94muAQOxVpi1jhnpKjOIqUbT81eELQPAzSXOke4ky4oCWYUXOcVpL31ZCO90xScwVSXRd7coqtgtB1Ng==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.10.1", + "@rc-component/context": "^1.4.0", + "classnames": "^2.2.5", + "rc-resize-observer": "^1.1.0", + "rc-util": "^5.41.0", + "rc-virtual-list": "^3.14.2" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" } }, - "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, + "node_modules/rc-tabs": { + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-15.4.0.tgz", + "integrity": "sha512-llKuyiAVqmXm2z7OrmhX5cNb2ueZaL8ZyA2P4R+6/72NYYcbEgOXibwHiQCFY2RiN3swXl53SIABi2CumUS02g==", + "license": "MIT", + "peer": true, "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "@babel/runtime": "^7.11.2", + "classnames": "2.x", + "rc-dropdown": "~4.2.0", + "rc-menu": "~9.16.0", + "rc-motion": "^2.6.2", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.34.1" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-textarea": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/rc-textarea/-/rc-textarea-1.8.2.tgz", + "integrity": "sha512-UFAezAqltyR00a8Lf0IPAyTd29Jj9ee8wt8DqXyDMal7r/Cg/nDt3e1OOv3Th4W6mKaZijjgwuPXhAfVNTN8sw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.1", + "rc-input": "~1.6.0", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.27.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" } }, - "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": ">=6" + "node_modules/rc-tooltip": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-6.2.1.tgz", + "integrity": "sha512-rws0duD/3sHHsD905Nex7FvoUGy2UBQRhTkKxeEvr2FB+r21HsOxcDJI0TzyO8NHhnAA8ILr8pfbSBg5Jj5KBg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.11.2", + "@rc-component/trigger": "^2.0.0", + "classnames": "^2.3.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" } }, - "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==", + "node_modules/rc-tree": { + "version": "5.10.1", + "resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-5.10.1.tgz", + "integrity": "sha512-FPXb3tT/u39mgjr6JNlHaUTYfHkVGW56XaGDahDpEFLGsnPxGcVLNTjcqoQb/GNbSCycl7tD7EvIymwOTP0+Yw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-motion": "^2.0.1", + "rc-util": "^5.16.1", + "rc-virtual-list": "^3.5.1" + }, "engines": { - "node": ">=6" + "node": ">=10.x" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" } }, - "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, + "node_modules/rc-tree-select": { + "version": "5.24.5", + "resolved": "https://registry.npmjs.org/rc-tree-select/-/rc-tree-select-5.24.5.tgz", + "integrity": "sha512-PnyR8LZJWaiEFw0SHRqo4MNQWyyZsyMs8eNmo68uXZWjxc7QqeWcjPPoONN0rc90c3HZqGF9z+Roz+GLzY5GXA==", + "license": "MIT", + "peer": true, "dependencies": { - "escape-goat": "^2.0.0" + "@babel/runtime": "^7.25.7", + "classnames": "2.x", + "rc-select": "~14.16.2", + "rc-tree": "~5.10.1", + "rc-util": "^5.43.0" }, - "engines": { - "node": ">=8" + "peerDependencies": { + "react": "*", + "react-dom": "*" } }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true + "node_modules/rc-trigger": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/rc-trigger/-/rc-trigger-1.11.5.tgz", + "integrity": "sha512-MBuUPw1nFzA4K7jQOwb7uvFaZFjXGd00EofUYiZ+l/fgKVq8wnLC0lkv36kwqM7vfKyftRo2sh7cWVpdPuNnnw==", + "peer": true, + "dependencies": { + "babel-runtime": "6.x", + "create-react-class": "15.x", + "prop-types": "15.x", + "rc-align": "2.x", + "rc-animate": "2.x", + "rc-util": "4.x" + } }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] + "node_modules/rc-trigger/node_modules/rc-util": { + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-4.21.1.tgz", + "integrity": "sha512-Z+vlkSQVc1l8O2UjR3WQ+XdWlhj5q9BMQNLk2iOBch75CqPfrJyGtcWMcnhRlNuDu0Ndtt4kLVO8JI8BrABobg==", + "license": "MIT", + "peer": true, + "dependencies": { + "add-dom-event-listener": "^1.1.0", + "prop-types": "^15.5.10", + "react-is": "^16.12.0", + "react-lifecycles-compat": "^3.0.4", + "shallowequal": "^1.1.0" + } }, - "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/rc-trigger/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==", + "license": "MIT", + "peer": true }, - "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/rc-upload": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/rc-upload/-/rc-upload-4.8.1.tgz", + "integrity": "sha512-toEAhwl4hjLAI1u8/CgKWt30BR06ulPa4iGQSMvSXoHzO88gPCslxqV/mnn4gJU7PDoltGIC9Eh+wkeudqgHyw==", + "license": "MIT", + "peer": true, "dependencies": { - "is-number": "^4.0.0", - "kind-of": "^6.0.0", - "math-random": "^1.0.1" + "@babel/runtime": "^7.18.3", + "classnames": "^2.2.5", + "rc-util": "^5.2.0" }, - "engines": { - "node": ">= 0.10.0" + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" } }, - "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/rc-util": { + "version": "5.44.3", + "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.44.3.tgz", + "integrity": "sha512-q6KCcOFk3rv/zD3MckhJteZxb0VjAIFuf622B7ElK4vfrZdAzs16XR5p3VTdy3+U5jfJU5ACz4QnhLSuAGe5dA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.18.3", + "react-is": "^18.2.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" } }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, + "node_modules/rc-virtual-list": { + "version": "3.16.1", + "resolved": "https://registry.npmjs.org/rc-virtual-list/-/rc-virtual-list-3.16.1.tgz", + "integrity": "sha512-algM5UsB7vrlPNr9lsZEH8s9KHkP8XbT/Y0qylyPkiM8mIOlSJLjBNADcmbYPEQCm4zW82mZRJuVHNzqqN0EAQ==", + "license": "MIT", + "peer": true, "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" + "@babel/runtime": "^7.20.0", + "classnames": "^2.2.6", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.36.0" }, - "bin": { - "rc": "cli.js" + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" } }, "node_modules/rc/node_modules/strip-json-comments": { @@ -14703,6 +18118,16 @@ } } }, + "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==", + "license": "MIT", + "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", @@ -14739,6 +18164,13 @@ "react": "^18.3.1" } }, + "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==", + "license": "MIT", + "peer": 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", @@ -14931,7 +18363,7 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "devOptional": true, + "dev": true, "dependencies": { "picomatch": "^2.2.1" }, @@ -14993,9 +18425,9 @@ "dev": true }, "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==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", + "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", "dev": true, "dependencies": { "regenerate": "^1.4.2" @@ -15004,6 +18436,13 @@ "node": ">=4" } }, + "node_modules/regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "license": "MIT", + "peer": true + }, "node_modules/regenerator-transform": { "version": "0.15.2", "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", @@ -15037,15 +18476,15 @@ } }, "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==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.1.1.tgz", + "integrity": "sha512-k67Nb9jvwJcJmVpw0jPttR1/zVfnKf8Km0IPatrU/zJ5XeG3+Slx0xLXs9HByJSzXzrlz5EDvN6yLNMDc2qdnw==", "dev": true, "dependencies": { - "@babel/regjsgen": "^0.8.0", "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.1.0", - "regjsparser": "^0.9.1", + "regenerate-unicode-properties": "^10.2.0", + "regjsgen": "^0.8.0", + "regjsparser": "^0.11.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.1.0" }, @@ -15077,27 +18516,24 @@ "node": ">=8" } }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "dev": true + }, "node_modules/regjsparser": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", - "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.11.2.tgz", + "integrity": "sha512-3OGZZ4HoLJkkAZx/48mTXJNlmqTGOzc0o9OWQPuWpkOlXXPbyN6OafCcoXUnBqE2D3f/T5L+pWc1kdEmnfnRsA==", "dev": true, "dependencies": { - "jsesc": "~0.5.0" + "jsesc": "~3.0.2" }, "bin": { "regjsparser": "bin/parser" } }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - } - }, "node_modules/rehackt": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/rehackt/-/rehackt-0.1.0.tgz", @@ -15150,7 +18586,6 @@ "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" } @@ -15175,6 +18610,13 @@ "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==" }, + "node_modules/resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==", + "license": "MIT", + "peer": true + }, "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", @@ -15362,7 +18804,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -15389,6 +18830,15 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, "node_modules/robust-predicates": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", @@ -15428,10 +18878,23 @@ "fsevents": "~2.3.2" } }, + "node_modules/rollup/node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.21.3.tgz", + "integrity": "sha512-P0UxIOrKNBFTQaXTxOH4RxuEBVCgEA5UTNV6Yz7z9QHnUJ7eLX9reOd/NYMO3+XZO2cco19mXTxDMXxit4R/eQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, "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==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", + "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==", + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -15440,7 +18903,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, "funding": [ { "type": "github", @@ -15548,13 +19010,13 @@ } }, "node_modules/sass": { - "version": "1.77.8", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.8.tgz", - "integrity": "sha512-4UHg6prsrycW20fqLGPShtEvo/WyHRVRHwOP4DzkUrObWoWI05QBSfzU71TVB7PFaL104TwNaHpjlWXAZbQiNQ==", + "version": "1.80.7", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.80.7.tgz", + "integrity": "sha512-MVWvN0u5meytrSjsU7AWsbhoXi1sc58zADXFllfZzbsBT1GHjjar6JwBINYPRrkx/zqnQ6uqbQuHgE95O+C+eQ==", "devOptional": true, "dependencies": { - "chokidar": ">=3.0.0 <4.0.0", - "immutable": "^4.0.0", + "chokidar": "^4.0.0", + "immutable": "^5.0.2", "source-map-js": ">=0.6.2 <2.0.0" }, "bin": { @@ -15562,6 +19024,37 @@ }, "engines": { "node": ">=14.0.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" + } + }, + "node_modules/sass/node_modules/chokidar": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz", + "integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==", + "devOptional": true, + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/sass/node_modules/readdirp": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz", + "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==", + "devOptional": true, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, "node_modules/saxes": { @@ -15584,6 +19077,29 @@ "loose-envify": "^1.1.0" } }, + "node_modules/screenfull": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/screenfull/-/screenfull-5.2.0.tgz", + "integrity": "sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/scroll-into-view-if-needed": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.1.0.tgz", + "integrity": "sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "compute-scroll-into-view": "^3.0.2" + } + }, "node_modules/semver": { "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", @@ -15622,7 +19138,6 @@ "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", @@ -15661,6 +19176,30 @@ "node": ">=0.10.0" } }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" + }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", + "license": "MIT", + "peer": true + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -15699,7 +19238,6 @@ "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", @@ -15713,10 +19251,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true + }, "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true }, "node_modules/simple-swizzle": { "version": "0.2.2", @@ -15882,6 +19427,12 @@ "node": ">=8" } }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true + }, "node_modules/statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -15891,6 +19442,32 @@ "node": ">= 0.6" } }, + "node_modules/std-env": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.8.0.tgz", + "integrity": "sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==", + "dev": true + }, + "node_modules/stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", + "dependencies": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + } + }, + "node_modules/stream-http": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.2.0.tgz", + "integrity": "sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==", + "dependencies": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "xtend": "^4.0.2" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -15908,6 +19485,13 @@ "node": ">=0.6.19" } }, + "node_modules/string-convert": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz", + "integrity": "sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==", + "license": "MIT", + "peer": true + }, "node_modules/string-hash": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz", @@ -15940,10 +19524,20 @@ "node": ">=8" } }, - "node_modules/string-width/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } }, "node_modules/string.prototype.matchall": { "version": "4.0.11", @@ -16043,10 +19637,23 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/strip-ansi": { + "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/strip-ansi-cjs": { + "name": "strip-ansi", "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -16108,8 +19715,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/stylis": { "version": "4.2.0", @@ -16120,6 +19726,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -16252,8 +19859,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true, - "peer": true + "dev": true }, "node_modules/throat": { "version": "6.0.2", @@ -16269,11 +19875,6 @@ "node": ">=8" } }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" - }, "node_modules/through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", @@ -16315,238 +19916,631 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/timers-browserify": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", + "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", + "dependencies": { + "setimmediate": "^1.0.4" + }, + "engines": { + "node": ">=0.6.0" + } + }, "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/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/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true + }, + "node_modules/tinycolor2": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", + "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==", + "license": "MIT", + "peer": true + }, + "node_modules/tinyexec": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.1.tgz", + "integrity": "sha512-WiCJLEECkO18gwqIp6+hJg0//p23HXp4S+gGtAKu3mI2F2/sXC4FvHvXvB0zJVVaTPhx1/tOwdbRsa1sOBIKqQ==", + "dev": true + }, + "node_modules/tinypool": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.2.tgz", + "integrity": "sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==", + "dev": true, + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/tinyrainbow": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz", + "integrity": "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", + "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "license": "MIT", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "node_modules/to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-object-path/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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toggle-selection": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", + "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==", + "license": "MIT", + "peer": true + }, + "node_modules/toml": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/toml/-/toml-2.3.6.tgz", + "integrity": "sha512-gVweAectJU3ebq//Ferr2JUY4WKSDe5N+z0FvjDncLGyHmIDoxgY/2Ie4qfEIDm4IS7OA6Rmdm7pdEEdMcV/xQ==" + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie": { + "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", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie/node_modules/universalify": { + "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" + } + }, + "node_modules/tr46": { + "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" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "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/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/ts-invariant": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.10.3.tgz", + "integrity": "sha512-uivwYcQaxAucv1CzRp2n/QdYPo4ILf9VXgH19zEIjFx2EJufV16P0JtJVpYHy89DItG6Kwj2oIUjrcK5au+4tQ==", + "dependencies": { + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tsconfig-paths/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "node_modules/tsx": { + "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.23.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/tsx/node_modules/@esbuild/aix-ppc64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz", + "integrity": "sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } }, - "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dependencies": { - "os-tmpdir": "~1.0.2" - }, + "node_modules/tsx/node_modules/@esbuild/android-arm": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.1.tgz", + "integrity": "sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=0.6.0" + "node": ">=18" } }, - "node_modules/tmp-promise": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/tmp-promise/-/tmp-promise-3.0.3.tgz", - "integrity": "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==", - "dependencies": { - "tmp": "^0.2.0" + "node_modules/tsx/node_modules/@esbuild/android-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.1.tgz", + "integrity": "sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" } }, - "node_modules/tmp-promise/node_modules/tmp": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", - "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "node_modules/tsx/node_modules/@esbuild/android-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.1.tgz", + "integrity": "sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=14.14" + "node": ">=18" } }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true + "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.1.tgz", + "integrity": "sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "node_modules/tsx/node_modules/@esbuild/darwin-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.1.tgz", + "integrity": "sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=4" + "node": ">=18" } }, - "node_modules/to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==", - "dependencies": { - "kind-of": "^3.0.2" - }, + "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.1.tgz", + "integrity": "sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=0.10.0" + "node": ">=18" } }, - "node_modules/to-object-path/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" - }, + "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.1.tgz", + "integrity": "sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=0.10.0" + "node": ">=18" } }, - "node_modules/to-readable-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", - "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "node_modules/tsx/node_modules/@esbuild/linux-arm": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.1.tgz", + "integrity": "sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==", + "cpu": [ + "arm" + ], "dev": true, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6" + "node": ">=18" } }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "devOptional": true, - "dependencies": { - "is-number": "^7.0.0" - }, + "node_modules/tsx/node_modules/@esbuild/linux-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.1.tgz", + "integrity": "sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8.0" + "node": ">=18" } }, - "node_modules/toml": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/toml/-/toml-2.3.6.tgz", - "integrity": "sha512-gVweAectJU3ebq//Ferr2JUY4WKSDe5N+z0FvjDncLGyHmIDoxgY/2Ie4qfEIDm4IS7OA6Rmdm7pdEEdMcV/xQ==" + "node_modules/tsx/node_modules/@esbuild/linux-ia32": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.1.tgz", + "integrity": "sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } }, - "node_modules/totalist": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", - "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "node_modules/tsx/node_modules/@esbuild/linux-loong64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.1.tgz", + "integrity": "sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==", + "cpu": [ + "loong64" + ], "dev": true, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6" + "node": ">=18" } }, - "node_modules/tough-cookie": { - "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==", + "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.1.tgz", + "integrity": "sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==", + "cpu": [ + "mips64el" + ], "dev": true, - "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6" + "node": ">=18" } }, - "node_modules/tough-cookie/node_modules/universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.1.tgz", + "integrity": "sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==", + "cpu": [ + "ppc64" + ], "dev": true, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 4.0.0" + "node": ">=18" } }, - "node_modules/tr46": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", - "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.1.tgz", + "integrity": "sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==", + "cpu": [ + "riscv64" + ], "dev": true, - "dependencies": { - "punycode": "^2.1.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/trim-lines": { - "version": "3.0.1", - "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/tsx/node_modules/@esbuild/linux-s390x": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.1.tgz", + "integrity": "sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "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==", + "node_modules/tsx/node_modules/@esbuild/linux-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.1.tgz", + "integrity": "sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=16" - }, - "peerDependencies": { - "typescript": ">=4.2.0" + "node": ">=18" } }, - "node_modules/ts-invariant": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.10.3.tgz", - "integrity": "sha512-uivwYcQaxAucv1CzRp2n/QdYPo4ILf9VXgH19zEIjFx2EJufV16P0JtJVpYHy89DItG6Kwj2oIUjrcK5au+4tQ==", - "dependencies": { - "tslib": "^2.1.0" - }, + "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.1.tgz", + "integrity": "sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/tsconfig-paths": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", - "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.1.tgz", + "integrity": "sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, - "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "node_modules/tsx/node_modules/@esbuild/sunos-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.1.tgz", + "integrity": "sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" } }, - "node_modules/tsconfig-paths/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "node_modules/tsx/node_modules/@esbuild/win32-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.1.tgz", + "integrity": "sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==", + "cpu": [ + "arm64" + ], "dev": true, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=4" + "node": ">=18" } }, - "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" - }, - "node_modules/tsx": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.1.tgz", - "integrity": "sha512-0flMz1lh74BR4wOvBjuh9olbnwqCPc35OOlfyzHba0Dc+QNUeWX/Gq2YTbnwcWPO3BMd8fkzRVrHcsR+a7z7rA==", + "node_modules/tsx/node_modules/@esbuild/win32-ia32": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.1.tgz", + "integrity": "sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==", + "cpu": [ + "ia32" + ], "dev": true, - "dependencies": { - "esbuild": "~0.23.0", - "get-tsconfig": "^4.7.5" - }, - "bin": { - "tsx": "dist/cli.mjs" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=18.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" + "node": ">=18" } }, "node_modules/tsx/node_modules/@esbuild/win32-x64": { @@ -16604,12 +20598,16 @@ "@esbuild/win32-x64": "0.23.1" } }, + "node_modules/tty-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", + "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==" + }, "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" }, @@ -16725,9 +20723,9 @@ } }, "node_modules/typedoc": { - "version": "0.26.7", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.26.7.tgz", - "integrity": "sha512-gUeI/Wk99vjXXMi8kanwzyhmeFEGv1LTdTQsiyIsmSYsBebvFxhbcyAx7Zjo4cMbpLGxM4Uz3jVIjksu/I2v6Q==", + "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", "markdown-it": "^14.1.0", @@ -16746,9 +20744,9 @@ } }, "node_modules/typedoc-plugin-markdown": { - "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==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/typedoc-plugin-markdown/-/typedoc-plugin-markdown-4.2.10.tgz", + "integrity": "sha512-PLX3pc1/7z13UJm4TDE9vo9jWGcClFUErXXtd5LdnoLjV6mynPpqZLU992DwMGFSRqJFZeKbVyqlNNeNHnk2tQ==", "engines": { "node": ">= 18" }, @@ -16838,13 +20836,12 @@ "node_modules/undici-types": { "version": "6.19.8", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", - "devOptional": true + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==" }, "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==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", "dev": true, "engines": { "node": ">=4" @@ -16864,9 +20861,9 @@ } }, "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", - "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", + "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", "dev": true, "engines": { "node": ">=4" @@ -16989,9 +20986,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", - "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", "funding": [ { "type": "opencollective", @@ -17007,8 +21004,8 @@ } ], "dependencies": { - "escalade": "^3.1.2", - "picocolors": "^1.0.1" + "escalade": "^3.2.0", + "picocolors": "^1.1.0" }, "bin": { "update-browserslist-db": "cli.js" @@ -17070,6 +21067,18 @@ "punycode": "^2.1.0" } }, + "node_modules/url": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.4.tgz", + "integrity": "sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==", + "dependencies": { + "punycode": "^1.4.1", + "qs": "^6.12.3" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/url-parse": { "version": "1.5.10", "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", @@ -17092,6 +21101,11 @@ "node": ">=4" } }, + "node_modules/url/node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==" + }, "node_modules/use-memo-one": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.3.tgz", @@ -17108,6 +21122,18 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -17171,6 +21197,18 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/virtualizedtableforantd4": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/virtualizedtableforantd4/-/virtualizedtableforantd4-1.3.1.tgz", + "integrity": "sha512-rW8KoToI2nt1jNtweXIUIiygi74XMzKLzUrrtZbGsQc7m3v68AaedPuf4CZcte+nosgYuPEWnAgjuI/KR8BVbg==", + "license": "MIT", + "peer": true, + "peerDependencies": { + "antd": "^4.0.0 || ^5.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/vite": { "version": "5.4.8", "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.8.tgz", @@ -17229,6 +21267,29 @@ } } }, + "node_modules/vite-node": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.5.tgz", + "integrity": "sha512-rd0QIgx74q4S1Rd56XIiL2cYEdyWn13cunYBIuqh9mpmQr7gGS0IxXoP8R6OaZtNQQLyXSWbd4rXKYUbhFpK5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.3.7", + "es-module-lexer": "^1.5.4", + "pathe": "^1.1.2", + "vite": "^5.0.0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, "node_modules/vite-plugin-environment": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/vite-plugin-environment/-/vite-plugin-environment-1.1.3.tgz", @@ -17237,6 +21298,21 @@ "vite": ">= 2.7" } }, + "node_modules/vite-plugin-node-polyfills": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/vite-plugin-node-polyfills/-/vite-plugin-node-polyfills-0.22.0.tgz", + "integrity": "sha512-F+G3LjiGbG8QpbH9bZ//GSBr9i1InSTkaulfUHFa9jkLqVGORFBoqc2A/Yu5Mmh1kNAbiAeKeK+6aaQUf3x0JA==", + "dependencies": { + "@rollup/plugin-inject": "^5.0.5", + "node-stdlib-browser": "^1.2.0" + }, + "funding": { + "url": "https://github.com/sponsors/davidmyersdev" + }, + "peerDependencies": { + "vite": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0" + } + }, "node_modules/vite-plugin-svgr": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/vite-plugin-svgr/-/vite-plugin-svgr-4.2.0.tgz", @@ -17251,28 +21327,6 @@ "vite": "^2.6.0 || 3 || 4 || 5" } }, - "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": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, "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", @@ -17498,12 +21552,6 @@ } } }, - "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", @@ -17517,9 +21565,9 @@ } }, "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==", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-5.1.3.tgz", + "integrity": "sha512-0bz+PDlLpGfP2CigeSKL9NFTF1KtXkeHGZSSaGQSuPZH77GhoiQaA8IjYgOaynSuwlDTolSUEU0ErVvju3NURg==", "dependencies": { "debug": "^4.1.1", "globrex": "^0.1.2", @@ -17553,6 +21601,77 @@ } } }, + "node_modules/vitest": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.5.tgz", + "integrity": "sha512-P4ljsdpuzRTPI/kbND2sDZ4VmieerR2c9szEZpjc+98Z9ebvnXmM5+0tHEKqYZumXqlvnmfWsjeFOjXVriDG7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "2.1.5", + "@vitest/mocker": "2.1.5", + "@vitest/pretty-format": "^2.1.5", + "@vitest/runner": "2.1.5", + "@vitest/snapshot": "2.1.5", + "@vitest/spy": "2.1.5", + "@vitest/utils": "2.1.5", + "chai": "^5.1.2", + "debug": "^4.3.7", + "expect-type": "^1.1.0", + "magic-string": "^0.30.12", + "pathe": "^1.1.2", + "std-env": "^3.8.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.1", + "tinypool": "^1.0.1", + "tinyrainbow": "^1.2.0", + "vite": "^5.0.0", + "vite-node": "2.1.5", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/node": "^18.0.0 || >=20.0.0", + "@vitest/browser": "2.1.5", + "@vitest/ui": "2.1.5", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" + }, "node_modules/void-elements": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", @@ -17600,18 +21719,10 @@ "loose-envify": "^1.0.0" } }, - "node_modules/wcwidth": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", - "dependencies": { - "defaults": "^1.0.3" - } - }, "node_modules/web-vitals": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-4.2.3.tgz", - "integrity": "sha512-/CFAm1mNxSmOj6i0Co+iGFJ58OS4NRGVP+AWS/l509uIK5a1bSoIVaHz/ZumpHTfHSZBpgrJ+wjfpAOrTHok5Q==" + "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", @@ -17748,7 +21859,6 @@ "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", @@ -17763,6 +21873,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/widest-line": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", @@ -17776,6 +21902,23 @@ } }, "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==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "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==", @@ -17864,7 +22007,6 @@ "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" } @@ -17886,7 +22028,6 @@ "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", @@ -17904,7 +22045,6 @@ "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" } @@ -17913,8 +22053,6 @@ "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" }, @@ -17922,6 +22060,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/yoctocolors-cjs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz", + "integrity": "sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/zen-observable": { "version": "0.8.15", "resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz", @@ -17939,11 +22089,39 @@ "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/zustand": { + "version": "4.5.5", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.5.tgz", + "integrity": "sha512-+0PALYNJNgK6hldkgDq2vLrw5f6g/jCInz52n9RTpropGgeAf/ioFUCdtsjCqu4gNhW9D01rUQBROoRjdzyn2Q==", + "license": "MIT", + "peer": true, + "dependencies": { + "use-sync-external-store": "1.2.2" + }, + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "@types/react": ">=16.8", + "immer": ">=9.0.6", + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + } + } + }, "node_modules/zwitch": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", diff --git a/package.json b/package.json index 5473cf84af..8e528c2ceb 100644 --- a/package.json +++ b/package.json @@ -5,25 +5,29 @@ "type": "module", "config-overrides-path": "scripts/config-overrides", "dependencies": { - "@apollo/client": "^3.11.4", + "@apollo/client": "^3.11.8", "@apollo/link-error": "^2.0.0-beta.3", "@apollo/react-testing": "^4.0.0", - "@dicebear/collection": "^8.0.2", - "@dicebear/core": "^8.0.2", + "@dicebear/collection": "^9.2.2", + "@dicebear/core": "^9.2.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.17.0", - "@mui/x-data-grid": "^7.16.0", - "@mui/x-date-pickers": "^7.11.1", - "@pdfme/generator": "^4.5.2", + "@mui/base": "^5.0.0-beta.61", + "@mui/icons-material": "^6.1.6", + "@mui/material": "^6.1.6", + "@mui/private-theming": "^6.1.6", + "@mui/system": "^6.1.6", + "@mui/x-charts": "^7.22.2", + "@mui/x-data-grid": "^7.22.1", + "@mui/x-date-pickers": "^7.18.0", + "@pdfme/common": "^5.2.11", + "@pdfme/generator": "^5.2.3", + "@pdfme/schemas": "^5.1.6", "@reduxjs/toolkit": "^2.3.0", - "@vitejs/plugin-react": "^4.3.2", + "@vitejs/plugin-react": "^4.3.3", "babel-plugin-transform-import-meta": "^2.2.1", "bootstrap": "^5.3.3", + "chart.js": "^4.4.6", "customize-cra": "^1.0.0", "dayjs": "^1.11.13", "dotenv": "^16.4.5", @@ -35,13 +39,16 @@ "i18next": "^23.15.1", "i18next-browser-languagedetector": "^8.0.0", "i18next-http-backend": "^2.6.1", - "inquirer": "^8.0.0", + "inquirer": "^11.0.2", "js-cookie": "^3.0.1", + "lcov-result-merger": "^5.0.1", "markdown-toc": "^1.2.0", - "prettier": "^3.3.2", + "prettier": "^3.3.3", + "prop-types": "^15.8.1", "react": "^18.3.1", "react-beautiful-dnd": "^13.1.1", "react-bootstrap": "^2.10.5", + "react-chartjs-2": "^5.2.0", "react-datepicker": "^7.5.0", "react-dom": "^18.3.1", "react-google-recaptcha": "^3.1.0", @@ -56,18 +63,22 @@ "redux": "^5.0.1", "redux-thunk": "^3.1.0", "sanitize-html": "^2.13.0", - "typedoc": "^0.26.7", - "typedoc-plugin-markdown": "^4.2.1", + "typedoc": "^0.26.10", + "typedoc-plugin-markdown": "^4.2.10", "typescript": "^5.6.3", "vite": "^5.4.8", "vite-plugin-environment": "^1.1.3", - "vite-tsconfig-paths": "^5.0.1", - "web-vitals": "^4.2.3" + "vite-plugin-node-polyfills": "^0.22.0", + "vite-tsconfig-paths": "^5.1.3", + "web-vitals": "^4.2.4" }, "scripts": { "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:vitest": "vitest run", + "test:vitest:watch": "vitest", + "test:vitest:coverage": "vitest run --coverage", "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 && python .github/workflows/eslint_disable_check.py", @@ -103,31 +114,34 @@ }, "devDependencies": { "@babel/plugin-proposal-private-property-in-object": "^7.21.11", - "@babel/preset-env": "^7.25.4", + "@babel/preset-env": "^7.26.0", "@babel/preset-react": "^7.25.7", - "@babel/preset-typescript": "^7.24.7", - "@testing-library/jest-dom": "^6.5.0", + "@babel/preset-typescript": "^7.26.0", + "@testing-library/jest-dom": "^6.6.3", "@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": "^22.5.4", + "@types/node": "^22.9.0", "@types/node-fetch": "^2.6.10", - "@types/react": "^18.3.3", + "@types/react": "^18.3.12", "@types/react-beautiful-dnd": "^13.1.8", - "@types/react-bootstrap": "^0.32.32", + "@types/react-bootstrap": "^0.32.37", + "@types/react-chartjs-2": "^2.5.7", "@types/react-datepicker": "^7.0.0", - "@types/react-dom": "^18.3.0", + "@types/react-dom": "^18.3.1", "@types/react-google-recaptcha": "^2.1.9", "@types/react-router-dom": "^5.1.8", "@types/sanitize-html": "^2.13.0", - "@typescript-eslint/eslint-plugin": "^8.8.1", + "@typescript-eslint/eslint-plugin": "^8.11.0", "@typescript-eslint/parser": "^8.5.0", + "@vitest/coverage-istanbul": "^2.1.5", "babel-jest": "^29.7.0", "cross-env": "^7.0.3", + "eslint": "^8.49.0", "eslint-config-prettier": "^9.1.0", - "eslint-plugin-import": "^2.30.0", + "eslint-plugin-import": "^2.31.0", "eslint-plugin-jest": "^28.8.0", "eslint-plugin-prettier": "^5.2.1", "eslint-plugin-react": "^7.37.1", @@ -140,9 +154,10 @@ "jest-preview": "^0.3.1", "lint-staged": "^15.2.8", "postcss-modules": "^6.0.0", - "sass": "^1.77.8", + "sass": "^1.80.7", "tsx": "^4.19.1", "vite-plugin-svgr": "^4.2.0", + "vitest": "^2.1.5", "whatwg-fetch": "^3.6.20" }, "resolutions": { diff --git a/public/images/svg/arrow-left.svg b/public/images/svg/arrow-left.svg new file mode 100644 index 0000000000..395c38fc25 --- /dev/null +++ b/public/images/svg/arrow-left.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/public/images/svg/arrow-right.svg b/public/images/svg/arrow-right.svg new file mode 100644 index 0000000000..bf754cec86 --- /dev/null +++ b/public/images/svg/arrow-right.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/public/images/svg/attendees.svg b/public/images/svg/attendees.svg new file mode 100644 index 0000000000..3864a85b7e --- /dev/null +++ b/public/images/svg/attendees.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/images/svg/feedback.svg b/public/images/svg/feedback.svg new file mode 100644 index 0000000000..649e84a1c9 --- /dev/null +++ b/public/images/svg/feedback.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/images/svg/options-outline.svg b/public/images/svg/options-outline.svg new file mode 100644 index 0000000000..939935eb11 --- /dev/null +++ b/public/images/svg/options-outline.svg @@ -0,0 +1,11 @@ + + + + + + diff --git a/public/images/svg/organization.svg b/public/images/svg/organization.svg new file mode 100644 index 0000000000..9bed28f87e --- /dev/null +++ b/public/images/svg/organization.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/public/images/svg/up-down.svg b/public/images/svg/up-down.svg new file mode 100644 index 0000000000..1dd7fdab1d --- /dev/null +++ b/public/images/svg/up-down.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 67e0909bfd..6c8882bcfd 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -30,6 +30,7 @@ "search": "Search", "description": "Description", "saveChanges": "Save Changes", + "gender": "Gender", "resetChanges": "Reset Changes", "displayImage": "Display Image", "enterEmail": "Enter Email", diff --git a/public/locales/en/errors.json b/public/locales/en/errors.json index 752c0db750..ffb0e6f146 100644 --- a/public/locales/en/errors.json +++ b/public/locales/en/errors.json @@ -7,5 +7,10 @@ "emailNotRegistered": "Email not registered", "notFoundMsg": "Oops! The Page you requested was not found!", "errorOccurredCouldntCreate": "An error occurred. Couldn't create {{entity}}", - "errorLoading": "Error occured while loading {{entity}} data" + "errorLoading": "Error occured while loading {{entity}} data", + "invalidPhoneNumber": "Please enter a valid phone number", + "invalidEducationGrade": "Please select a valid education grade", + "invalidEmploymentStatus": "Please select a valid employment status", + "invalidMaritalStatus": "Please select a valid marital status", + "error400": "The submitted information is invalid. Please check your inputs and try again" } diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json index a3415f199f..a6cb90d3d1 100644 --- a/public/locales/en/translation.json +++ b/public/locales/en/translation.json @@ -1,4 +1,16 @@ { + "leaderboard": { + "title": "Leaderboard", + "searchByVolunteer": "Search By Volunteer", + "mostHours": "Most Hours", + "leastHours": "Least Hours", + "timeFrame": "Time Frame", + "allTime": "All Time", + "weekly": "This Week", + "monthly": "This Month", + "yearly": "This Year", + "noVolunteers": "No Volunteers Found!" + }, "loginPage": { "title": "Talawa Admin", "fromPalisadoes": "An open source application by Palisadoes Foundation volunteers", @@ -266,7 +278,9 @@ "members": "members", "admins": "admins", "requests": "requests", - "talawaApiUnavailable": "talawaApiUnavailable" + "talawaApiUnavailable": "talawaApiUnavailable", + "volunteerRankings": "Volunteer Rankings", + "noVolunteers": "No Volunteers Found!" }, "organizationPeople": { "title": "Talawa Members", @@ -320,7 +334,8 @@ "noTagsFound": "No tags found", "removeUserTag": "Delete Tag", "removeUserTagMessage": "Do you want to delete this tag?", - "addChildTag": "Add a Sub Tag" + "addChildTag": "Add a Sub Tag", + "enterTagName": "Enter Tag Name" }, "manageTag": { "title": "Tag Details", @@ -332,7 +347,34 @@ "successfullyUnassigned": "Tag unassigned from user", "addPeople": "Add People", "add": "Add", - "subTags": "Sub Tags" + "subTags": "Sub Tags", + "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", + "noMoreMembersFound": "No more members found" }, "userListCard": { "addAdmin": "Add Admin", @@ -372,11 +414,13 @@ "recurringEvent": "Recurring Event", "isPublic": "Is Public", "isRegistrable": "Is Registrable", + "createChat": "Create Chat", "createEvent": "Create Event", "enterFilter": "Enter Filter", "enterTitle": "Enter Title", "enterDescrip": "Enter Description", "searchEventName": "Search Event Name", + "searchMemberName": "Search Member Name", "eventType": "Event Type", "eventCreated": "Congratulations! The Event is created.", "customRecurrence": "Custom Recurrence", @@ -433,7 +477,7 @@ "successfulDeletion": "Action Item deleted successfully", "title": "Action Items", "category": "Category", - "allotedHours": "Alloted Hours", + "allottedHours": "Allotted Hours", "latestDueDate": "Latest Due Date", "earliestDueDate": "Earliest Due Date", "updateActionItem": "Update Action Item", @@ -442,7 +486,12 @@ "close": "close", "eventActionItems": "eventActionItems", "no": "no", - "yes": "yes" + "yes": "yes", + "individuals": "Individuals", + "groups": "Groups", + "assignTo": "Assign To", + "volunteers": "Volunteers", + "volunteerGroups": "Volunteer Groups" }, "organizationAgendaCategory": { "agendaCategoryDetails": "Agenda Category Details", @@ -505,6 +554,7 @@ "recurringEvent": "Recurring Event", "isPublic": "Is Public", "isRegistrable": "Is Registrable", + "createChat": "Create Chat", "updatePost": "Update Post", "eventDetails": "Event Details", "eventDeleted": "Event deleted successfully.", @@ -702,13 +752,55 @@ "noResultsFoundFor": "noResultsFoundFor" }, "eventManagement": { - "title": "Event Management", + "title": "Event Management Dashboard", "dashboard": "Dashboard", "registrants": "Registrants", - "eventActions": "Event Actions", - "eventAgendas": "Event Agendas", - "eventStats": "Event Statistics", - "to": "TO" + "attendance": "Attendance", + "actions": "Actions", + "agendas": "Agendas", + "statistics": "Statistics", + "to": "TO", + "volunteers": "Volunteers" + }, + "eventAttendance": { + "historical_statistics": "Historical Statistics", + "Search member": "Search member", + "Member Name": "Member Name", + "Status": "Status", + "Events Attended": "Events Attended", + "Task Assigned": "Task Assigned", + "Member": "Member", + "Admin": "Admin", + "loading": "Loading...", + "noAttendees": "Attendees not Found" + }, + "eventRegistrant": { + "sort": "Sort", + "allRegistrants": "All Registrants", + "eventRegistrantsTable": "Event Registrants Table", + "serialNumber": "Serial Number", + "registrant": "Registrant", + "registeredAt": "Registered At", + "createdAt": "Created At", + "addRegistrant": "Add Registrant", + "noRegistrantsFound": "No Registrants Found." + }, + "onSpotAttendee": { + "title": "On-spot Attendee", + "enterFirstName": "Enter First Name", + "enterLastName": "Enter Last Name", + "enterEmail": "Enter Email", + "enterPhoneNo": "Enter Phone Number", + "selectGender": "Select Gender", + "invalidDetailsMessage": "Please fill in all required fields", + "orgIdMissing": "Organization ID is missing. Please try again.", + "attendeeAddedSuccess": "Attendee added successfully!", + "addAttendee": "Add", + "phoneNumber": "Phone No.", + "addingAttendee": "Adding...", + "male": "Male", + "female": "Female", + "other": "Other" }, "forgotPassword": { "title": "Talawa Forgot Password", @@ -844,7 +936,7 @@ "register": "register" }, "addOnStore": { - "title": "Add On Store", + "title": "Plugin Store", "searchName": "Ex: Donations", "search": "Search", "enable": "Enabled", @@ -865,6 +957,7 @@ "memberDetail": { "title": "User Details", "addAdmin": "Add Admin", + "noeventsAttended": "No Events Attended", "alreadyIsAdmin": "Member is already an Admin", "organizations": "Organizations", "events": "Events", @@ -884,6 +977,8 @@ "state": "State", "city": "City", "personalInfoHeading": "Personal Information", + "viewAll": "View All", + "eventsAttended": "Events Attended", "contactInfoHeading": "Contact Information", "actionsHeading": "Actions", "personalDetailsHeading": "Profile Details", @@ -902,7 +997,12 @@ "delete": "delete", "saveChanges": "saveChanges", "joined": "joined", - "talawaApiUnavailable": "talawaApiUnavailable" + "talawaApiUnavailable": "talawaApiUnavailable", + "unassignUserTag": "Unassign Tag", + "unassignUserTagMessage": "Do you want to remove the tag from this user?", + "successfullyUnassigned": "Tag unassigned from user", + "tagsAssigned": "Tags Assigned", + "noTagsAssigned": "No Tags Assigned" }, "people": { "title": "People", @@ -1013,6 +1113,8 @@ "postNowVisibleInFeed": "Post now visible in feed" }, "settings": { + "eventAttended": "Events Attended", + "noeventsAttended": "No Events Attended", "profileSettings": "Profile Settings", "gender": "Gender", "phoneNumber": "Phone Number", @@ -1104,6 +1206,7 @@ "enterDescription": "Enter Description", "publicEvent": "Is Public", "registerable": "Is Registerable", + "createChat": "Create Chat", "monthlyCalendarView": "Monthly Calendar", "yearlyCalendarView": "Yearly Calender", "startTime": "startTime", @@ -1138,7 +1241,7 @@ "RstartDate": "Select Start Date", "RendDate": "Select End Date", "RClose": "Close the window", - "addNew": "Create new advertisement", + "addNew": "Create", "EXname": "Ex. Cookie Shop", "EXlink": "Ex. http://yourwebsite.com/photo", "createAdvertisement": "Create Advertisement", @@ -1159,14 +1262,22 @@ "endOfResults": "endOfResults" }, "userChat": { + "add": "Add", "chat": "Chat", "search": "Search", "messages": "Messages", - "contacts": "Contacts" + "contacts": "Contacts", + "create": "Create", + "newChat": "New Chat", + "newGroupChat": "New Group Chat", + "groupInfo": "Group Info", + "members": "Members", + "addMembers": "Add Members" }, "userChatRoom": { "selectContact": "Select a contact to start conversation", - "sendMessage": "Send Message" + "sendMessage": "Send Message", + "reply": "Reply" }, "orgProfileField": { "loading": "Loading...", @@ -1315,5 +1426,83 @@ }, "userPledges": { "title": "My Pledges" + }, + "leaveOrganization": { + "title": "Leave Organization" + }, + "eventVolunteers": { + "volunteers": "Volunteers", + "volunteer": "Volunteer", + "volunteerGroups": "Volunteer Groups", + "individuals": "Individuals", + "groups": "Groups", + "status": "Status", + "noVolunteers": "No Volunteers", + "noVolunteerGroups": "No Volunteer Groups", + "add": "Add", + "mostHoursVolunteered": "Most Hours Volunteered", + "leastHoursVolunteered": "Least Hours Volunteered", + "accepted": "Accepted", + "addVolunteer": "Add Volunteer", + "removeVolunteer": "Remove Volunteer", + "volunteerAdded": "Volunteer added successfully", + "volunteerRemoved": "Volunteer removed successfully", + "volunteerGroupCreated": "Volunteer group created successfully", + "volunteerGroupUpdated": "Volunteer group updated successfully", + "volunteerGroupDeleted": "Volunteer group deleted successfully", + "removeVolunteerMsg": "Are you sure you want to remove this Volunteer?", + "deleteVolunteerGroupMsg": "Are you sure you want to delete this Volunteer Group?", + "leader": "Leader", + "group": "Group", + "createGroup": "Create Group", + "updateGroup": "Update Group", + "deleteGroup": "Delete Group", + "volunteersRequired": "Volunteers Required", + "volunteerDetails": "Volunteer Details", + "hoursVolunteered": "Hours Volunteered", + "groupDetails": "Group Details", + "creator": "Creator", + "requests": "Requests", + "noRequests": "No Requests", + "latest": "Latest", + "earliest": "Earliest", + "requestAccepted": "Request accepted successfully", + "requestRejected": "Request rejected successfully", + "details": "Details", + "manageGroup": "Manage Group", + "mostVolunteers": "Most Volunteers", + "leastVolunteers": "Least Volunteers" + }, + "userVolunteer": { + "title": "Volunteership", + "name": "Title", + "upcomingEvents": "Upcoming Events", + "requests": "Requests", + "invitations": "Invitations", + "groups": "Volunteer Groups", + "actions": "Actions", + "searchByName": "Search by Name", + "latestEndDate": "Latest End Date", + "earliestEndDate": "Earliest End Date", + "noEvents": "No Upcoming Events", + "volunteer": "Volunteer", + "volunteered": "Volunteered", + "join": "Join", + "joined": "Joined", + "searchByEventName": "Search by Event title", + "filter": "Filter", + "groupInvite": "Group Invite", + "individualInvite": "Individual Invite", + "noInvitations": "No Invitations", + "accept": "Accept", + "reject": "Reject", + "receivedLatest": "Received Latest", + "receivedEarliest": "Received Earliest", + "invitationAccepted": "Invitation accepted successfully", + "invitationRejected": "Invitation rejected successfully", + "volunteerSuccess": "Requested to volunteer successfully", + "recurring": "Recurring", + "groupInvitationSubject": "Invitation to join volunteer group", + "eventInvitationSubject": "Invitation to volunteer for event" } } diff --git a/public/locales/fr/common.json b/public/locales/fr/common.json index c1aadd7dbe..132a913c7d 100644 --- a/public/locales/fr/common.json +++ b/public/locales/fr/common.json @@ -36,6 +36,7 @@ "emailAddress": "Adresse e-mail", "email": "E-mail", "name": "Nom", + "gender": "Genre", "desc": "Description", "enterPassword": "Entrer le mot de passe", "password": "Mot de passe", diff --git a/public/locales/fr/errors.json b/public/locales/fr/errors.json index e9a7cf4fd9..ae53237404 100644 --- a/public/locales/fr/errors.json +++ b/public/locales/fr/errors.json @@ -7,5 +7,10 @@ "emailNotRegistered": "Email non enregistré", "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}}" + "errorLoading": "Une erreur s'est produite lors du chargement des données {{entity}}", + "invalidPhoneNumber": "Veuillez entrer un numéro de téléphone valide", + "invalidEducationGrade": "Veuillez sélectionner un niveau d'études valide", + "invalidEmploymentStatus": "Veuillez sélectionner un statut d'emploi valide", + "invalidMaritalStatus": "Veuillez sélectionner un état matrimonial valide", + "error400": "Réponse non réussie. Code d'état 400 reçu du serveur" } diff --git a/public/locales/fr/translation.json b/public/locales/fr/translation.json index 6f7332057b..416d00c4b4 100644 --- a/public/locales/fr/translation.json +++ b/public/locales/fr/translation.json @@ -1,4 +1,16 @@ { + "leaderboard": { + "title": "Tableau des Leaders", + "searchByVolunteer": "Recherche par Bénévole", + "mostHours": "Le Plus d'Heures", + "leastHours": "Le Moins d'Heures", + "timeFrame": "Période", + "allTime": "Tout le Temps", + "weekly": "Cette Semaine", + "monthly": "Ce Mois", + "yearly": "Cette Année", + "noVolunteers": "Aucun Bénévole Trouvé!" + }, "loginPage": { "title": "Administrateur Talawa", "fromPalisadoes": "Une application open source réalisée par les bénévoles de la Fondation Palisadoes", @@ -266,7 +278,9 @@ "members": "Membres", "admins": "Administrateurs", "requests": "Demandes", - "talawaApiUnavailable": "API Talawa indisponible" + "talawaApiUnavailable": "API Talawa indisponible", + "volunteerRankings": "Classement des Bénévoles", + "noVolunteers": "Aucun Bénévole Trouvé!" }, "organizationPeople": { "title": "Membres Talawa", @@ -320,7 +334,8 @@ "noTagsFound": "Aucune étiquette trouvée", "removeUserTag": "Supprimer l'Étiquette", "removeUserTagMessage": "Voulez-vous supprimer cette étiquette ?", - "addChildTag": "Ajouter une Sous-Étiquette" + "addChildTag": "Ajouter une Sous-Étiquette", + "enterTagName": "Entrez le nom de l'étiquette" }, "manageTag": { "title": "Détails de l'étiquette", @@ -332,7 +347,34 @@ "successfullyUnassigned": "Étiquette retirée de l'utilisateur", "addPeople": "Ajouter des personnes", "add": "Ajouter", - "subTags": "Sous-étiquettes" + "subTags": "Sous-étiquettes", + "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", + "noMoreMembersFound": "Aucun autre membre trouvé" }, "userListCard": { "addAdmin": "Ajouter un administrateur", @@ -372,6 +414,7 @@ "endTime": "Heure de fin", "allDay": "Toute la journée", "recurringEvent": "Événement récurrent", + "searchMemberName": "Rechercher le nom du membre", "isPublic": "est public", "isRegistrable": "Est enregistrable", "createEvent": "Créer un évènement", @@ -396,53 +439,59 @@ "startDate": "Date de début", "endDate": "Date de fin", "talawaApiUnavailable": "API Talawa indisponible", - "done": "Fait" + "done": "Fait", + "createChat": "Créer une discussion" }, "organizationActionItems": { - "actionItemCategory": "Catégorie d'élément d'action", - "actionItemDetails": "Détails de l'action", - "actionItemCompleted": "Élément d'action terminé", - "assignee": "Cessionnaire", - "assigner": "Assigner", - "assignmentDate": "Date d'affectation", + "actionItemCategory": "Catégorie de l'Action", + "actionItemDetails": "Détails de l'Action", + "actionItemCompleted": "Action Terminée", + "assignee": "Attribué à", + "assigner": "Assignateur", + "assignmentDate": "Date d'Attribution", "active": "Actif", - "clearFilters": "Effacer les filtres", - "completionDate": "Date d'achèvement", - "createActionItem": "Créer un élément d'action", - "deleteActionItem": "Supprimer l'élément d'action", - "deleteActionItemMsg": "Voulez-vous supprimer cette action ?", + "clearFilters": "Effacer les Filtres", + "completionDate": "Date de Complétion", + "createActionItem": "Créer une Action", + "deleteActionItem": "Supprimer l'Action", + "deleteActionItemMsg": "Voulez-vous supprimer cette action?", "details": "Détails", - "dueDate": "Date d'échéance", - "earliest": "Le plus tôt", - "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", - "actionItemActive": "Actif", - "markCompletion": "Marquer l'achèvement", - "actionItemStatus": "Statut de l'action", - "postCompletionNotes": "Notes post-achèvement", - "selectActionItemCategory": "Sélectionnez une catégorie d'élément d'action", - "selectAssignee": "Sélectionnez un responsable", + "dueDate": "Date d'Échéance", + "earliest": "Le Plus Ancien", + "editActionItem": "Modifier l'Action", + "isCompleted": "Terminé", + "latest": "Le Plus Récent", + "makeActive": "Rendre Actif", + "noActionItems": "Aucune Action", + "options": "Options", + "preCompletionNotes": "Notes Pré-Complétion", + "actionItemActive": "Action Active", + "markCompletion": "Marquer comme Terminé", + "actionItemStatus": "État de l'Action", + "postCompletionNotes": "Notes Post-Complétion", + "selectActionItemCategory": "Sélectionnez une Catégorie d'Action", + "selectAssignee": "Sélectionner un Attribué", "status": "Statut", - "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", + "successfulCreation": "Action créée avec succès", + "successfulUpdation": "Action mise à jour avec succès", + "successfulDeletion": "Action supprimée avec succès", + "title": "Actions", "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?", + "allottedHours": "Heures Attribuées", + "latestDueDate": "Date d'Échéance la Plus Récente", + "earliestDueDate": "Date d'Échéance la Plus Ancienne", + "updateActionItem": "Mettre à Jour l'Action", + "noneUpdated": "Aucun champ n'a été mis à jour", + "updateStatusMsg": "Voulez-vous vraiment marquer cette action comme en attente?", "close": "Fermer", - "eventActionItems": "Éléments d'action d'événement", + "eventActionItems": "Actions de l'Événement", "no": "Non", - "yes": "Oui" + "yes": "Oui", + "individuals": "Individus", + "groups": "Groupes", + "assignTo": "Attribuer à", + "volunteers": "Bénévoles", + "volunteerGroups": "Groupes de Bénévoles" }, "organizationAgendaCategory": { "agendaCategoryDetails": "Détails de la catégorie d'ordre du jour", @@ -531,7 +580,8 @@ "registerEvent": "Inscrire à l'événement", "close": "Fermer", "talawaApiUnavailable": "API Talawa non disponible", - "done": "Terminé" + "done": "Terminé", + "createChat": "Créer une discussion" }, "funds": { "title": "Fonds", @@ -705,10 +755,12 @@ "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": "À" + "attendance": "Présence", + "actions": "Actions", + "agendas": "Ordres du jour", + "statistics": "Statistiques", + "to": "À", + "volunteers": "Bénévoles" }, "forgotPassword": { "title": "Talawa Mot de passe oublié", @@ -865,6 +917,7 @@ "memberDetail": { "title": "Détails de l'utilisateur", "addAdmin": "Ajouter un administrateur", + "noeventsAttended": "Aucun événement assisté", "alreadyIsAdmin": "Le membre est déjà un administrateur", "organizations": "Organisations", "events": "Événements", @@ -884,6 +937,8 @@ "state": "État", "city": "Ville", "personalInfoHeading": "Informations personnelles", + "eventsAttended": "Événements attenus", + "viewAll": "Voir tout", "contactInfoHeading": "Coordonnées", "actionsHeading": "Actions", "personalDetailsHeading": "Détails du profil", @@ -902,7 +957,12 @@ "delete": "Supprimer", "saveChanges": "Enregistrer les modifications", "joined": "Rejoint", - "talawaApiUnavailable": "API Talawa non disponible" + "talawaApiUnavailable": "API Talawa non disponible", + "unassignUserTag": "Désassigner l'étiquette", + "unassignUserTagMessage": "Voulez-vous retirer l'étiquette de cet utilisateur?", + "successfullyUnassigned": "Étiquette retirée de l'utilisateur", + "tagsAssigned": "étiquettes assignées", + "noTagsAssigned": "Aucune étiquette assignée" }, "people": { "title": "Personnes", @@ -1012,7 +1072,49 @@ "article": "Article", "postNowVisibleInFeed": "Le post est maintenant visible dans le fil d'actualité" }, + "eventAttendance": { + "historical_statistics": "Statistiques historiques", + "Search member": "Rechercher un membre", + "Member Name": "Nom du membre", + "Status": "Statut", + "Events Attended": "Événements assistés", + "Task Assigned": "Tâche assignée", + "Member": "Membre", + "Admin": "Administrateur", + "loading": "Chargement...", + "noAttendees": "Aucun participant trouvé" + }, + "eventRegistrant": { + "sort": "Trier", + "allRegistrants": "Tous les inscrits", + "eventRegistrantsTable": "Table des inscrits à l'événement", + "serialNumber": "Numéro de série", + "registrant": "Inscrit", + "registeredAt": "Enregistré le", + "createdAt": "Créé le", + "addRegistrant": "Ajouter un inscrit", + "noRegistrantsFound": "Aucun inscrit trouvé." + }, + "onSpotAttendee": { + "title": "Participant sur place", + "enterFirstName": "Entrez le prénom", + "enterLastName": "Entrez le nom de famille", + "enterEmail": "Entrez l'e-mail", + "enterPhoneNo": "Entrez le numéro de téléphone", + "selectGender": "Sélectionnez le sexe", + "invalidDetailsMessage": "Veuillez remplir tous les champs obligatoires", + "orgIdMissing": "L'ID de l'organisation est manquant. Veuillez réessayer.", + "attendeeAddedSuccess": "Participant ajouté avec succès!", + "addAttendee": "Ajouter", + "phoneNumber": "Numéro de téléphone", + "addingAttendee": "Ajout en cours...", + "male": "Homme", + "female": "Femme", + "other": "Autre" + }, "settings": { + "eventAttended": "Événements Assistés", + "noeventsAttended": "Aucun événement assisté", "profileSettings": "Paramètres de profil", "gender": "Genre", "phoneNumber": "Numéro de téléphone", @@ -1115,7 +1217,8 @@ "eventDescription": "Description de l'événement", "eventLocation": "Lieu de l'événement", "startDate": "Date de début", - "endDate": "Date de fin" + "endDate": "Date de fin", + "createChat": "Créer une discussion" }, "userEventCard": { "starts": "Départs", @@ -1159,14 +1262,22 @@ "endOfResults": "Fin des résultats" }, "userChat": { + "add": "Ajouter", "chat": "Chat", "contacts": "Contacts", "search": "rechercher", - "messages": "messages" + "messages": "messages", + "create": "créer", + "newChat": "nouvelle discussion", + "newGroupChat": "Nouvelle discussion de groupe", + "groupInfo": "Informations sur le groupe", + "members": "Membres", + "addMembers": "Add Members" }, "userChatRoom": { "selectContact": "Sélectionnez un contact pour démarrer la conversation", - "sendMessage": "Envoyer le message" + "sendMessage": "Envoyer le message", + "reply": "répondre" }, "orgProfileField": { "loading": "Chargement...", @@ -1315,5 +1426,83 @@ }, "userPledges": { "title": "Mes Promesses" + }, + "leaveOrganization": { + "title": "Quitter l'organisation" + }, + "eventVolunteers": { + "volunteers": "Bénévoles", + "volunteer": "Bénévole", + "volunteerGroups": "Groupes de Bénévoles", + "individuals": "Individus", + "groups": "Groupes", + "status": "Statut", + "noVolunteers": "Aucun Bénévole", + "noVolunteerGroups": "Aucun Groupe de Bénévoles", + "add": "Ajouter", + "mostHoursVolunteered": "Le Plus d'Heures de Bénévolat", + "leastHoursVolunteered": "Le Moins d'Heures de Bénévolat", + "accepted": "Accepté", + "addVolunteer": "Ajouter un Bénévole", + "removeVolunteer": "Supprimer le Bénévole", + "volunteerAdded": "Bénévole ajouté avec succès", + "volunteerRemoved": "Bénévole supprimé avec succès", + "volunteerGroupCreated": "Groupe de bénévoles créé avec succès", + "volunteerGroupUpdated": "Groupe de bénévoles mis à jour avec succès", + "volunteerGroupDeleted": "Groupe de bénévoles supprimé avec succès", + "removeVolunteerMsg": "Êtes-vous sûr de vouloir supprimer ce bénévole?", + "deleteVolunteerGroupMsg": "Êtes-vous sûr de vouloir supprimer ce groupe de bénévoles?", + "leader": "Chef", + "group": "Groupe", + "createGroup": "Créer un Groupe", + "updateGroup": "Mettre à Jour le Groupe", + "deleteGroup": "Supprimer le Groupe", + "volunteersRequired": "Bénévoles Requis", + "volunteerDetails": "Détails du Bénévole", + "hoursVolunteered": "Heures de Bénévolat", + "groupDetails": "Détails du Groupe", + "creator": "Créateur", + "requests": "Demandes", + "noRequests": "Aucune Demande", + "latest": "Le Plus Récent", + "earliest": "Le Plus Ancien", + "requestAccepted": "Demande acceptée avec succès", + "requestRejected": "Demande rejetée avec succès", + "details": "Détails", + "manageGroup": "Gérer le Groupe", + "mostVolunteers": "Le plus de bénévoles", + "leastVolunteers": "Le moins de bénévoles" + }, + "userVolunteer": { + "title": "Volontariat", + "name": "Titre", + "upcomingEvents": "Événements à Venir", + "requests": "Demandes", + "invitations": "Invitations", + "groups": "Groupes de Bénévoles", + "actions": "Actions", + "searchByName": "Rechercher par Nom", + "latestEndDate": "Date de Fin la Plus Récente", + "earliestEndDate": "Date de Fin la Plus Ancienne", + "noEvents": "Aucun Événement à Venir", + "volunteer": "Bénévole", + "volunteered": "A Bénévolé", + "join": "Rejoindre", + "joined": "Rejoint", + "searchByEventName": "Rechercher par Titre d'Événement", + "filter": "Filtrer", + "groupInvite": "Invitation de Groupe", + "individualInvite": "Invitation Individuelle", + "noInvitations": "Aucune Invitation", + "accept": "Accepter", + "reject": "Rejeter", + "receivedLatest": "Reçu le Plus Récemment", + "receivedEarliest": "Reçu en Premier", + "invitationAccepted": "Invitation acceptée avec succès", + "invitationRejected": "Invitation rejetée avec succès", + "volunteerSuccess": "Demande de bénévolat envoyée avec succès", + "recurring": "Récurrent", + "groupInvitationSubject": "Invitation à rejoindre le groupe de bénévoles", + "eventInvitationSubject": "Invitation à faire du bénévolat pour l'événement" } } diff --git a/public/locales/hi/common.json b/public/locales/hi/common.json index 7484872071..f312424f1d 100644 --- a/public/locales/hi/common.json +++ b/public/locales/hi/common.json @@ -27,6 +27,7 @@ "yes": "हाँ", "no": "नहीं", "filter": "फ़िल्टर", + "gender": "लिंग", "search": "खोज", "description": "विवरण", "saveChanges": "परिवर्तनों को सुरक्षित करें", diff --git a/public/locales/hi/errors.json b/public/locales/hi/errors.json index 63b6c3f5d3..64f9523180 100644 --- a/public/locales/hi/errors.json +++ b/public/locales/hi/errors.json @@ -7,5 +7,10 @@ "emailNotRegistered": "ईमेल पंजीकृत नहीं है", "notFoundMsg": "उफ़! ", "errorOccurredCouldntCreate": "एक त्रुटि हुई। {{entity}} नहीं बना सके", - "errorLoading": "{{entity}} डेटा लोड करते समय त्रुटि हुई" + "errorLoading": "{{entity}} डेटा लोड करते समय त्रुटि हुई", + "invalidPhoneNumber": "कृपया एक मान्य फोन-नंबर दर्ज करे", + "invalidEducationGrade": "कृपया एक शिक्षा ग्रेड चुनें", + "invalidEmploymentStatus": "कृपया वैध रोजगार स्थिति चुनें", + "invalidMaritalStatus": "कृपया वैध वैवाहिक स्थिति चुनें", + "error400": "आपकी जानकारी सहेजी नहीं जा सकी। कृपया अपनी प्रविष्टियों की जांच करें और पुनः प्रयास करें।" } diff --git a/public/locales/hi/translation.json b/public/locales/hi/translation.json index 95d704daca..6abb8abefc 100644 --- a/public/locales/hi/translation.json +++ b/public/locales/hi/translation.json @@ -1,4 +1,16 @@ { + "leaderboard": { + "title": "लीडरबोर्ड", + "searchByVolunteer": "स्वयंसेवक द्वारा खोजें", + "mostHours": "सबसे अधिक घंटे", + "leastHours": "सबसे कम घंटे", + "timeFrame": "समय सीमा", + "allTime": "सभी समय", + "weekly": "इस सप्ताह", + "monthly": "इस माह", + "yearly": "इस वर्ष", + "noVolunteers": "कोई स्वयंसेवक नहीं मिला!" + }, "loginPage": { "title": "तालावा व्यवस्थापक", "fromPalisadoes": "Palisadoes फाउंडेशन स्वयंसेवकों द्वारा विकसित एक ओपन-सोर्स एप्लिकेशन", @@ -266,7 +278,9 @@ "members": "सदस्य", "admins": "प्रशासक", "requests": "अनुरोध", - "talawaApiUnavailable": "तालावा एपीआई अनुपलब्ध" + "talawaApiUnavailable": "तालावा एपीआई अनुपलब्ध", + "volunteerRankings": "स्वयंसेवक रैंकिंग", + "noVolunteers": "कोई स्वयंसेवक नहीं मिला!" }, "organizationPeople": { "title": "तालावा सदस्य", @@ -320,7 +334,8 @@ "noTagsFound": "कोई टैग नहीं मिला", "removeUserTag": "टैग हटाएँ", "removeUserTagMessage": "क्या आप इस टैग को हटाना चाहते हैं?", - "addChildTag": "उप-टैग जोड़ें" + "addChildTag": "उप-टैग जोड़ें", + "enterTagName": "टैग का नाम दर्ज करें" }, "manageTag": { "title": "टैग विवरण", @@ -332,7 +347,34 @@ "successfullyUnassigned": "उपयोगकर्ता से टैग हटा दिया गया", "addPeople": "लोगों को जोड़ें", "add": "जोड़ें", - "subTags": "उप-टैग्स" + "subTags": "उप-टैग्स", + "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": "सभी टैग", + "noMoreMembersFound": "कोई और सदस्य नहीं मिला" }, "userListCard": { "addAdmin": "व्यवस्थापक जोड़ें", @@ -367,6 +409,7 @@ "filterByDescription": "विवरण के अनुसार फ़िल्टर करें", "addEvent": "कार्यक्रम जोड़ें", "eventDetails": "घटना की जानकारी", + "searchMemberName": "सदस्य का नाम खोजें", "eventTitle": "शीर्षक", "startTime": "समय शुरू", "endTime": "अंत समय", @@ -396,53 +439,59 @@ "startDate": "प्रारंभ तिथि", "endDate": "समाप्ति तिथि", "talawaApiUnavailable": "Talawa API अनुपलब्ध", - "done": "पूर्ण" + "done": "पूर्ण", + "createChat": "चैट बनाएं" }, "organizationActionItems": { - "actionItemCategory": "कार्य आइटम श्रेणी", - "actionItemDetails": "कार्रवाई मद विवरण", - "actionItemCompleted": "कार्य आइटम पूर्ण हुआ", - "assignee": "संपत्ति-भागी", - "assigner": "असाइनर", - "assignmentDate": "असाइनमेंट दिनांक", + "actionItemCategory": "क्रिया वस्तु श्रेणी", + "actionItemDetails": "क्रिया वस्तु विवरण", + "actionItemCompleted": "क्रिया वस्तु पूरी", + "assignee": "प्राप्तकर्ता", + "assigner": "सौंपने वाला", + "assignmentDate": "आवंटन तिथि", "active": "सक्रिय", "clearFilters": "फ़िल्टर साफ़ करें", - "completionDate": "पूरा करने की तिथि", - "createActionItem": "कार्रवाई आइटम बनाएं", - "deleteActionItem": "क्रिया आइटम हटाएँ", - "deleteActionItemMsg": "क्या आप इस क्रिया आइटम को हटाना चाहते हैं?", + "completionDate": "पूर्णता तिथि", + "createActionItem": "क्रिया वस्तु बनाएँ", + "deleteActionItem": "क्रिया वस्तु हटाएँ", + "deleteActionItemMsg": "क्या आप इस क्रिया वस्तु को हटाना चाहते हैं?", "details": "विवरण", - "dueDate": "नियत तारीख", - "earliest": "जल्द से जल्द", - "editActionItem": "क्रिया आइटम संपादित करें", - "isCompleted": "पुरा होना।", + "dueDate": "समाप्ति तिथि", + "earliest": "सबसे पहले", + "editActionItem": "क्रिया वस्तु संपादित करें", + "isCompleted": "पूर्ण", "latest": "नवीनतम", - "makeActive": "सक्रिय", - "noActionItems": "कोई एक्शन आइटम नहीं", + "makeActive": "सक्रिय बनाएं", + "noActionItems": "कोई क्रिया वस्तु नहीं", "options": "विकल्प", - "preCompletionNotes": "समापन पूर्व नोट्स", - "actionItemActive": "सक्रिय", - "markCompletion": "पूर्णता चिह्नित करें", - "actionItemStatus": "कार्रवाई मद स्थिति", - "postCompletionNotes": "समापन के बाद के नोट्स", - "selectActionItemCategory": "एक क्रिया आइटम श्रेणी का चयन करें", - "selectAssignee": "एक समनुदेशिती का चयन करें", + "preCompletionNotes": "पूर्व-पूर्णता नोट्स", + "actionItemActive": "सक्रिय क्रिया वस्तु", + "markCompletion": "पूर्णता को चिह्नित करें", + "actionItemStatus": "क्रिया वस्तु स्थिति", + "postCompletionNotes": "पूर्णता के बाद नोट्स", + "selectActionItemCategory": "क्रिया वस्तु श्रेणी चुनें", + "selectAssignee": "प्राप्तकर्ता चुनें", "status": "स्थिति", - "successfulCreation": "कार्रवाई आइटम सफलतापूर्वक बनाया गया", - "successfulUpdation": "कार्रवाई आइटम सफलतापूर्वक अपडेट किया गया", - "successfulDeletion": "कार्रवाई आइटम सफलतापूर्वक हटा दिया गया", - "title": "एक्शन आइटम्स", + "successfulCreation": "क्रिया वस्तु सफलतापूर्वक बनाई गई", + "successfulUpdation": "क्रिया वस्तु सफलतापूर्वक अद्यतन की गई", + "successfulDeletion": "क्रिया वस्तु सफलतापूर्वक हटाई गई", + "title": "क्रिया वस्तुएँ", "category": "श्रेणी", - "allotedHours": "आवंटित घंटे", - "latestDueDate": "सबसे अधिक नियत तिथि", - "earliestDueDate": "सबसे पहले की नियत तिथि", - "updateActionItem": "कार्य आइटम अपडेट करें", - "noneUpdated": "कोई फ़ील्ड अपडेट नहीं किया गया", - "updateStatusMsg": "क्या आप वाकई इस कार्य आइटम को लंबित के रूप में चिह्नित करना चाहते हैं?", + "allottedHours": "आवंटित घंटे", + "latestDueDate": "नवीनतम समाप्ति तिथि", + "earliestDueDate": "प्रारंभिक समाप्ति तिथि", + "updateActionItem": "क्रिया वस्तु अपडेट करें", + "noneUpdated": "कोई फ़ील्ड अपडेट नहीं की गई", + "updateStatusMsg": "क्या आप वाकई इस क्रिया वस्तु को लंबित के रूप में चिह्नित करना चाहते हैं?", "close": "बंद करें", - "eventActionItems": "कार्यक्रम कार्रवाई आइटम", + "eventActionItems": "घटना क्रिया वस्तुएं", "no": "नहीं", - "yes": "हाँ" + "yes": "हाँ", + "individuals": "व्यक्तियों", + "groups": "समूहों", + "assignTo": "सौंपें", + "volunteers": "स्वयंसेवक", + "volunteerGroups": "स्वयंसेवक समूह" }, "organizationAgendaCategory": { "agendaCategoryDetails": "एजेंडा श्रेणी विवरण", @@ -531,7 +580,8 @@ "registerEvent": "कार्यक्रम के लिए पंजीकरण करें", "close": "बंद करें", "talawaApiUnavailable": "Talawa API अनुपलब्ध", - "done": "समाप्त" + "done": "समाप्त", + "createChat": "चैट बनाएं" }, "funds": { "title": "फंड", @@ -705,10 +755,12 @@ "title": "इवेंट मैनेजमेंट", "dashboard": "डैशबोर्ड", "registrants": "कुलसचिव", - "eventActions": "घटना क्रियाएँ", - "eventAgendas": "इवेंट एजेंडा", - "eventStats": "घटना सांख्यिकी", - "to": "को" + "attendance": "उपस्थिति", + "actions": "कार्य", + "agendas": "एजेंडे", + "statistics": "आँकड़े", + "to": "को", + "volunteers": "स्वयंसेवक" }, "forgotPassword": { "title": "तलावा पासवर्ड भूल गए", @@ -865,6 +917,7 @@ "memberDetail": { "title": "उपयोगकर्ता विवरण", "addAdmin": "व्यवस्थापक जोड़ें", + "noeventsAttended": "कोई कार्यक्रम में भाग नहीं लिया", "alreadyIsAdmin": "सदस्य पहले से ही एक व्यवस्थापक है", "organizations": "संगठनों", "events": "आयोजन", @@ -884,6 +937,8 @@ "state": "राज्य", "city": "शहर", "personalInfoHeading": "व्यक्तिगत जानकारी", + "eventsAttended": "ईवेंट्स जिन्हें भाग लिया गया है", + "viewAll": "सभी को देखें", "contactInfoHeading": "संपर्क जानकारी", "actionsHeading": "कार्रवाई", "personalDetailsHeading": "प्रोफ़ाइल विवरण", @@ -902,7 +957,12 @@ "delete": "हटाएं", "saveChanges": "परिवर्तन सहेजें", "joined": "शामिल हुए", - "talawaApiUnavailable": "Talawa API अनुपलब्ध" + "talawaApiUnavailable": "Talawa API अनुपलब्ध", + "unassignUserTag": "टैग को हटाएं", + "unassignUserTagMessage": "क्या आप इस उपयोगकर्ता से टैग हटाना चाहते हैं?", + "successfullyUnassigned": "उपयोगकर्ता से टैग हटा दिया गया", + "tagsAssigned": "टैग सौंपे गए", + "noTagsAssigned": "कोई टैग सौंपा नहीं गया" }, "people": { "title": "लोग", @@ -1012,7 +1072,49 @@ "article": "लेख", "postNowVisibleInFeed": "पोस्ट अब फीड में दिखाई दे रहा है" }, + "eventAttendance": { + "historical_statistics": "ऐतिहासिक आंकड़े", + "Search member": "सदस्य खोजें", + "Member Name": "सदस्य का नाम", + "Status": "स्थिति", + "Events Attended": "भाग लिए गए कार्यक्रम", + "Task Assigned": "सौंपा गया कार्य", + "Member": "सदस्य", + "Admin": "व्यवस्थापक", + "loading": "लोड हो रहा है", + "noAttendees": "कोई प्रतिभागी नहीं मिला" + }, + "eventRegistrant": { + "sort": "छांटें", + "allRegistrants": "सभी पंजीकृत व्यक्ति", + "eventRegistrantsTable": "इवेंट पंजीकृत व्यक्ति तालिका", + "serialNumber": "सिरियल नंबर", + "registrant": "पंजीकृत व्यक्ति", + "registeredAt": "पंजीकरण तिथि", + "createdAt": "निर्माण तिथि", + "addRegistrant": "पंजीकृत व्यक्ति जोड़ें", + "noRegistrantsFound": "कोई पंजीकृत व्यक्ति नहीं मिला" + }, + "onSpotAttendee": { + "title": "ऑन-स्पॉट प्रतिभागी", + "enterFirstName": "प्रथम नाम दर्ज करें", + "enterLastName": "अंतिम नाम दर्ज करें", + "enterEmail": "ईमेल दर्ज करें", + "enterPhoneNo": "फ़ोन नंबर दर्ज करें", + "selectGender": "लिंग चुनें", + "invalidDetailsMessage": "कृपया सभी आवश्यक फ़ील्ड भरें", + "orgIdMissing": "संगठन आईडी गायब है। कृपया पुनः प्रयास करें।", + "attendeeAddedSuccess": "प्रतिभागी सफलतापूर्वक जोड़ा गया!", + "addAttendee": "जोड़ें", + "phoneNumber": "फ़ोन नंबर", + "addingAttendee": "जोड़ा जा रहा है...", + "male": "पुरुष", + "female": "महिला", + "other": "अन्य" + }, "settings": { + "noeventsAttended": "कोई कार्यक्रम में उपस्थित नहीं", + "eventAttended": "भाग लिए गए कार्यक्रम", "profileSettings": "पार्श्वचित्र समायोजन", "gender": "लिंग", "phoneNumber": "फ़ोन नंबर", @@ -1115,7 +1217,8 @@ "eventDescription": "कार्यक्रम विवरण", "eventLocation": "कार्यक्रम स्थान", "startDate": "प्रारंभ तिथि", - "endDate": "समाप्ति तिथि" + "endDate": "समाप्ति तिथि", + "createChat": "चैट बनाएं" }, "userEventCard": { "starts": "प्रारंभ होगा", @@ -1159,14 +1262,22 @@ "endOfResults": "परिणाम समाप्त" }, "userChat": { + "add": "जोड़ें", "chat": "बात करना", "contacts": "संपर्क", "search": "खोज", - "messages": "संदेश" + "messages": "संदेश", + "create": "बनाएं", + "newChat": "नई चैट", + "newGroupChat": "नया समूह चैट", + "groupInfo": "समूह जानकारी", + "members": "सदस्यों", + "addMembers": "सदस्य जोड़ें" }, "userChatRoom": { "selectContact": "बातचीत शुरू करने के लिए एक संपर्क चुनें", - "sendMessage": "मेसेज भेजें" + "sendMessage": "मेसेज भेजें", + "reply": "जवाब" }, "orgProfileField": { "loading": "लोड हो रहा है...", @@ -1315,5 +1426,83 @@ }, "userPledges": { "title": "मेरी प्रतिज्ञाएँ" + }, + "leaveOrganization": { + "title": "संगठन छोड़ें" + }, + "eventVolunteers": { + "volunteers": "स्वयंसेवक", + "volunteer": "स्वयंसेवक", + "volunteerGroups": "स्वयंसेवक समूह", + "individuals": "व्यक्ति", + "groups": "समूह", + "status": "स्थिति", + "noVolunteers": "कोई स्वयंसेवक नहीं", + "noVolunteerGroups": "कोई स्वयंसेवक समूह नहीं", + "add": "जोड़ें", + "mostHoursVolunteered": "सबसे अधिक घंटे स्वयंसेवा", + "leastHoursVolunteered": "सबसे कम घंटे स्वयंसेवा", + "accepted": "स्वीकृत", + "addVolunteer": "स्वयंसेवक जोड़ें", + "removeVolunteer": "स्वयंसेवक हटाएं", + "volunteerAdded": "स्वयंसेवक सफलतापूर्वक जोड़ा गया", + "volunteerRemoved": "स्वयंसेवक सफलतापूर्वक हटाया गया", + "volunteerGroupCreated": "स्वयंसेवक समूह सफलतापूर्वक बनाया गया", + "volunteerGroupUpdated": "स्वयंसेवक समूह सफलतापूर्वक अपडेट किया गया", + "volunteerGroupDeleted": "स्वयंसेवक समूह सफलतापूर्वक हटाया गया", + "removeVolunteerMsg": "क्या आप वाकई इस स्वयंसेवक को हटाना चाहते हैं?", + "deleteVolunteerGroupMsg": "क्या आप वाकई इस स्वयंसेवक समूह को हटाना चाहते हैं?", + "leader": "नेता", + "group": "समूह", + "createGroup": "समूह बनाएं", + "updateGroup": "समूह अपडेट करें", + "deleteGroup": "समूह हटाएं", + "volunteersRequired": "आवश्यक स्वयंसेवक", + "volunteerDetails": "स्वयंसेवक विवरण", + "hoursVolunteered": "स्वयंसेवा घंटे", + "groupDetails": "समूह विवरण", + "creator": "निर्माता", + "requests": "अनुरोध", + "noRequests": "कोई अनुरोध नहीं", + "latest": "नवीनतम", + "earliest": "प्रारंभिक", + "requestAccepted": "अनुरोध सफलतापूर्वक स्वीकृत", + "requestRejected": "अनुरोध सफलतापूर्वक अस्वीकृत", + "details": "विवरण", + "manageGroup": "समूह प्रबंधित करें", + "mostVolunteers": "सबसे अधिक स्वयंसेवक", + "leastVolunteers": "सबसे कम स्वयंसेवक" + }, + "userVolunteer": { + "title": "स्वयंसेवकता", + "name": "शीर्षक", + "upcomingEvents": "आगामी कार्यक्रम", + "requests": "अनुरोध", + "invitations": "निमंत्रण", + "groups": "स्वयंसेवक समूह", + "actions": "क्रियाएँ", + "searchByName": "नाम से खोजें", + "latestEndDate": "नवीनतम समाप्ति तिथि", + "earliestEndDate": "प्रारंभिक समाप्ति तिथि", + "noEvents": "कोई आगामी कार्यक्रम नहीं", + "volunteer": "स्वयंसेवक", + "volunteered": "स्वयंसेवित", + "join": "शामिल हों", + "joined": "शामिल हुआ", + "searchByEventName": "कार्यक्रम शीर्षक से खोजें", + "filter": "फ़िल्टर", + "groupInvite": "समूह निमंत्रण", + "individualInvite": "व्यक्तिगत निमंत्रण", + "noInvitations": "कोई निमंत्रण नहीं", + "accept": "स्वीकारें", + "reject": "अस्वीकार करें", + "receivedLatest": "हाल में प्राप्त", + "receivedEarliest": "सबसे पहले प्राप्त", + "invitationAccepted": "निमंत्रण सफलतापूर्वक स्वीकार किया गया", + "invitationRejected": "निमंत्रण सफलतापूर्वक अस्वीकृत", + "volunteerSuccess": "स्वयंसेवक के रूप में अनुरोध सफलतापूर्वक किया गया", + "recurring": "पुनरावृत्ति", + "groupInvitationSubject": "स्वयंसेवक समूह में शामिल होने के लिए निमंत्रण", + "eventInvitationSubject": "कार्यक्रम के लिए स्वयंसेवक बनने का निमंत्रण" } } diff --git a/public/locales/sp/common.json b/public/locales/sp/common.json index d0b918c925..2c06daac5e 100644 --- a/public/locales/sp/common.json +++ b/public/locales/sp/common.json @@ -16,6 +16,7 @@ "register": "Register", "menu": "Menu", "settings": "Settings", + "gender": "Género", "users": "Users", "requests": "Requests", "OR": "OR", diff --git a/public/locales/sp/errors.json b/public/locales/sp/errors.json index 39b579abac..7489356b5e 100644 --- a/public/locales/sp/errors.json +++ b/public/locales/sp/errors.json @@ -7,5 +7,10 @@ "emailNotRegistered": "Email not registered", "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}}" + "errorLoading": "Ocurrió un error al cargar los datos de {{entity}}", + "invalidPhoneNumber": "Por favor, introduzca un número de teléfono válido", + "invalidEducationGrade": "Por favor seleccione un grado de educación válido", + "invalidEmploymentStatus": "Por favor seleccione un estado de empleo válido", + "invalidMaritalStatus": "Por favor seleccione un estado civil válido", + "error400": "Respuesta no exitosa. Se recibió el código de estado 400 del servidor" } diff --git a/public/locales/sp/translation.json b/public/locales/sp/translation.json index bd2959808d..79d7436c39 100644 --- a/public/locales/sp/translation.json +++ b/public/locales/sp/translation.json @@ -1,4 +1,16 @@ { + "leaderboard": { + "title": "Tabla de Clasificación", + "searchByVolunteer": "Buscar por Voluntario", + "mostHours": "Más Horas", + "leastHours": "Menos Horas", + "timeFrame": "Período", + "allTime": "Todo el Tiempo", + "weekly": "Esta Semana", + "monthly": "Este Mes", + "yearly": "Este Año", + "noVolunteers": "¡No Se Encontraron Voluntarios!" + }, "loginPage": { "title": "Administrador Talawa", "fromPalisadoes": "Una aplicación de código abierto de los voluntarios de la Fundación palisados", @@ -266,7 +278,9 @@ "noPostsPresent": "No Hay Publicaciones Presentes", "membershipRequests": "Solicitudes de Membresía", "noMembershipRequests": "No Hay Solicitudes de Membresía", - "talawaApiUnavailable": "El servicio Talawa-API no está disponible. ¿Está funcionando? Compruebe también la conectividad de su red." + "talawaApiUnavailable": "El servicio Talawa-API no está disponible. ¿Está funcionando? Compruebe también la conectividad de su red.", + "volunteerRankings": "Clasificación de Voluntarios", + "noVolunteers": "¡No Se Encontraron Voluntarios!" }, "organizationPeople": { "title": "Miembros Talawa", @@ -320,7 +334,8 @@ "noTagsFound": "No se encontraron etiquetas", "removeUserTag": "Eliminar Etiqueta", "removeUserTagMessage": "¿Desea eliminar esta etiqueta?", - "addChildTag": "Agregar una Sub Etiqueta" + "addChildTag": "Agregar una Sub Etiqueta", + "enterTagName": "Ingrese el nombre de la etiqueta" }, "manageTag": { "title": "Detalles de la Etiqueta", @@ -332,7 +347,34 @@ "successfullyUnassigned": "Etiqueta desasignada del usuario", "addPeople": "Agregar Personas", "add": "Agregar", - "subTags": "Subetiquetas" + "subTags": "Subetiquetas", + "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", + "noMoreMembersFound": "No se encontraron más miembros" }, "userListCard": { "joined": "Unido", @@ -372,6 +414,7 @@ "description": "Descripción", "location": "Ubicación", "startDate": "Fecha de inicio", + "searchMemberName": "Buscar nombre de miembro", "endDate": "Fecha final", "startTime": "Hora de inicio", "endTime": "Hora de finalización", @@ -396,53 +439,59 @@ "on": "En", "after": "Después de", "occurences": "ocurrencias", - "done": "Hecho" + "done": "Hecho", + "createChat": "Crear chat" }, "organizationActionItems": { - "actionItemCategory": "Categoría del ítem de acción", - "actionItemActive": "Elemento de acción activo", - "actionItemCompleted": "Elemento de acción completado", - "actionItemDetails": "Detalles del ítem de acción", - "actionItemStatus": "Estado del elemento de acción", + "actionItemCategory": "Categoría de Acción", + "actionItemDetails": "Detalles de la Acción", + "actionItemCompleted": "Acción Completada", "assignee": "Asignado", "assigner": "Asignador", - "assignmentDate": "Fecha de asignación", + "assignmentDate": "Fecha de Asignación", "active": "Activo", - "clearFilters": "Borrar filtros", - "close": "Cerrar", - "completionDate": "Fecha de finalización", - "createActionItem": "Crear ítem de acción", - "deleteActionItem": "Eliminar ítem de acción", - "deleteActionItemMsg": "¿Desea eliminar este ítem de acción?", + "clearFilters": "Limpiar Filtros", + "completionDate": "Fecha de Finalización", + "createActionItem": "Crear Acción", + "deleteActionItem": "Eliminar Acción", + "deleteActionItemMsg": "¿Desea eliminar esta acción?", "details": "Detalles", - "dueDate": "Fecha de vencimiento", - "earliest": "Lo más temprano", - "editActionItem": "Editar ítem de acción", - "eventActionItems": "Elementos de acción del evento", + "dueDate": "Fecha de Vencimiento", + "earliest": "El Más Antiguo", + "editActionItem": "Editar Acción", "isCompleted": "Completado", - "latest": "Lo más reciente", - "makeActive": "Activar", - "markCompletion": "Marcar finalización", - "no": "No", - "noActionItems": "No hay ítems de acción", + "latest": "El Más Reciente", + "makeActive": "Hacer Activo", + "noActionItems": "No Hay Acciones", "options": "Opciones", - "preCompletionNotes": "Notas previas a la finalización", - "postCompletionNotes": "Notas posteriores a la finalización", - "selectActionItemCategory": "Seleccione una categoría de ítem de acción", - "selectAssignee": "Seleccione un asignado", + "preCompletionNotes": "Notas Pre-Compleción", + "actionItemActive": "Acción Activa", + "markCompletion": "Marcar como Completado", + "actionItemStatus": "Estado de la Acción", + "postCompletionNotes": "Notas de Finalización", + "selectActionItemCategory": "Seleccionar una Categoría de Acción", + "selectAssignee": "Seleccionar Asignado", "status": "Estado", - "successfulCreation": "Ítem de acción creado con éxito", - "successfulUpdation": "Ítem de acción actualizado con éxito", - "successfulDeletion": "Ítem de acción eliminado con éxito", - "title": "Ítems de acción", - "yes": "Sí", + "successfulCreation": "Acción creada con éxito", + "successfulUpdation": "Acción actualizada con éxito", + "successfulDeletion": "Acción eliminada con éxito", + "title": "Acciones", "category": "Categoría", - "allotedHours": "Horas Asignadas", + "allottedHours": "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?" + "earliestDueDate": "Fecha de Vencimiento Más Antigua", + "updateActionItem": "Actualizar Acción", + "noneUpdated": "Ningún campo fue actualizado", + "updateStatusMsg": "¿Está seguro de que desea marcar esta acción como pendiente?", + "close": "Cerrar", + "eventActionItems": "Acciones del Evento", + "no": "No", + "yes": "Sí", + "individuals": "Individuos", + "groups": "Grupos", + "assignTo": "Asignar a", + "volunteers": "Voluntarios", + "volunteerGroups": "Grupos de Voluntarios" }, "organizationAgendaCategory": { "agendaCategoryDetails": "Detalles de la categoría de la agenda", @@ -531,7 +580,8 @@ "on": "En", "after": "Después de", "occurences": "ocurrencias", - "done": "Hecho" + "done": "Hecho", + "createChat": "Crear chat" }, "funds": { "title": "Fondos", @@ -706,10 +756,12 @@ "title": "Gestión de eventos", "dashboard": "Tablero", "registrants": "Inscritos", - "eventActions": "Acciones del evento", - "eventAgendas": "Agendas de eventos", - "eventStats": "Estadísticas del evento", - "to": "A" + "attendance": "Asistencia", + "actions": "Acciones", + "agendas": "Agendas", + "statistics": "Estadísticas", + "to": "A", + "volunteers": "Voluntarios" }, "forgotPassword": { "title": "Talawa olvidó su contraseña", @@ -866,6 +918,7 @@ "memberDetail": { "title": "Detalles del usuario", "addAdmin": "Agregar administrador", + "noeventsAttended": "No hay eventos asistidos", "alreadyIsAdmin": "El Miembro ya es Administrador", "organizations": "Organizaciones", "events": "Eventos", @@ -888,6 +941,8 @@ "state": "Estado", "city": "Ciudad", "personalInfoHeading": "Información Personal", + "viewAll": "Ver todo", + "eventsAttended": "Eventos Asistidos", "contactInfoHeading": "Información de Contacto", "actionsHeading": "Acciones", "personalDetailsHeading": "Detalles del perfil", @@ -903,7 +958,12 @@ "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.", "deleteUser": "Eliminar usuario", - "userType": "Tipo de usuario" + "userType": "Tipo de usuario", + "unassignUserTag": "Desasignar Etiqueta", + "unassignUserTagMessage": "¿Desea eliminar la etiqueta de este usuario?", + "successfullyUnassigned": "Etiqueta desasignada del usuario", + "tagsAssigned": "Etiquetas asignadas", + "noTagsAssigned": "No se asignaron etiquetas" }, "userLogin": { "login": "Acceso", @@ -1013,8 +1073,52 @@ "article": "Artículo", "postNowVisibleInFeed": "Publicar ahora visible en el feed" }, + + "eventAttendance": { + "historical_statistics": "Estadísticas históricas", + "Search member": "Buscar miembro", + "Member Name": "Nombre del miembro", + "Status": "Estado", + "Events Attended": "Eventos asistidos", + "Task Assigned": "Tarea asignada", + "Member": "Miembro", + "Admin": "Administrador", + "loading": "Cargando...", + "noAttendees": "No se encontraron asistentes" + }, + + "eventRegistrant": { + "sort": "Ordenar", + "allRegistrants": "Todos los registrados", + "eventRegistrantsTable": "Tabla de registrados del evento", + "serialNumber": "Número de serie", + "registrant": "Registrado", + "registeredAt": "Registrado en", + "createdAt": "Creado en", + "addRegistrant": "Agregar registrado", + "noRegistrantsFound": "No se encontraron registrados" + }, + "onSpotAttendee": { + "title": "Asistente en el lugar", + "enterFirstName": "Ingrese el nombre", + "enterLastName": "Ingrese el apellido", + "enterEmail": "Ingrese el correo electrónico", + "enterPhoneNo": "Ingrese el número de teléfono", + "selectGender": "Seleccione el género", + "invalidDetailsMessage": "Por favor complete todos los campos requeridos", + "orgIdMissing": "Falta el ID de la organización. Por favor, inténtelo de nuevo.", + "attendeeAddedSuccess": "¡Asistente agregado exitosamente!", + "addAttendee": "Agregar", + "phoneNumber": "Número de teléfono", + "addingAttendee": "Agregando...", + "male": "Masculino", + "female": "Femenino", + "other": "Otro" + }, "settings": { "settings": "Ajustes", + "eventAttended": "Événements Assistés", + "noeventsAttended": "No hay eventos asistidos", "profileSettings": "Configuración de perfil", "firstName": "Nombre de pila", "lastName": "Apellido", @@ -1116,7 +1220,8 @@ "publicEvent": "Es público", "registerable": "Es registrable", "monthlyCalendarView": "Calendario mensual", - "yearlyCalendarView": "Calendario anual" + "yearlyCalendarView": "Calendario anual", + "createChat": "Crear chat" }, "userEventCard": { "location": "Ubicación", @@ -1160,14 +1265,22 @@ "createAdvertisement": "Crear publicidad" }, "userChat": { + "add": "Agregar", "chat": "Charlar", "search": "Buscar", "contacts": "Contactos", - "messages": "Mensajes" + "messages": "Mensajes", + "create": "crear", + "newChat": "nueva charla", + "newGroupChat": "Nuevo chat grupal", + "groupInfo": "Información del grupo", + "members": "Miembros", + "addMembers": "Add Members" }, "userChatRoom": { "selectContact": "Seleccione un contacto para iniciar una conversación", - "sendMessage": "Enviar mensaje" + "sendMessage": "Enviar mensaje", + "reply": "responder" }, "orgProfileField": { "loading": "Cargando..", @@ -1316,5 +1429,83 @@ }, "userPledges": { "title": "Mis Promesas" + }, + "leaveOrganization": { + "title": "Dejar la organización" + }, + "eventVolunteers": { + "volunteers": "Voluntarios", + "volunteer": "Voluntario", + "volunteerGroups": "Grupos de Voluntarios", + "individuals": "Individuos", + "groups": "Grupos", + "status": "Estado", + "noVolunteers": "No Hay Voluntarios", + "noVolunteerGroups": "No Hay Grupos de Voluntarios", + "add": "Agregar", + "mostHoursVolunteered": "Más Horas de Voluntariado", + "leastHoursVolunteered": "Menos Horas de Voluntariado", + "accepted": "Aceptado", + "addVolunteer": "Agregar Voluntario", + "removeVolunteer": "Eliminar Voluntario", + "volunteerAdded": "Voluntario agregado con éxito", + "volunteerRemoved": "Voluntario eliminado con éxito", + "volunteerGroupCreated": "Grupo de voluntarios creado con éxito", + "volunteerGroupUpdated": "Grupo de voluntarios actualizado con éxito", + "volunteerGroupDeleted": "Grupo de voluntarios eliminado con éxito", + "removeVolunteerMsg": "¿Está seguro de que desea eliminar a este Voluntario?", + "deleteVolunteerGroupMsg": "¿Está seguro de que desea eliminar este Grupo de Voluntarios?", + "leader": "Líder", + "group": "Grupo", + "createGroup": "Crear Grupo", + "updateGroup": "Actualizar Grupo", + "deleteGroup": "Eliminar Grupo", + "volunteersRequired": "Voluntarios Necesarios", + "volunteerDetails": "Detalles del Voluntario", + "hoursVolunteered": "Horas de Voluntariado", + "groupDetails": "Detalles del Grupo", + "creator": "Creador", + "requests": "Solicitudes", + "noRequests": "No Hay Solicitudes", + "latest": "Más Reciente", + "earliest": "Más Antiguo", + "requestAccepted": "Solicitud aceptada con éxito", + "requestRejected": "Solicitud rechazada con éxito", + "details": "Detalles", + "manageGroup": "Gestionar Grupo", + "mostVolunteers": "La mayoría de voluntarios", + "leastVolunteers": "Menos voluntarios" + }, + "userVolunteer": { + "title": "Voluntariado", + "name": "Título", + "upcomingEvents": "Próximos Eventos", + "requests": "Solicitudes", + "invitations": "Invitaciones", + "groups": "Grupos de Voluntarios", + "actions": "Acciones", + "searchByName": "Buscar por Nombre", + "latestEndDate": "Fecha de Finalización Más Reciente", + "earliestEndDate": "Fecha de Finalización Más Antigua", + "noEvents": "No Hay Próximos Eventos", + "volunteer": "Voluntario", + "volunteered": "Voluntariado", + "join": "Unirse", + "joined": "Unido", + "searchByEventName": "Buscar por Título del Evento", + "filter": "Filtrar", + "groupInvite": "Invitación de Grupo", + "individualInvite": "Invitación Individual", + "noInvitations": "No Hay Invitaciones", + "accept": "Aceptar", + "reject": "Rechazar", + "receivedLatest": "Recibido Recientemente", + "receivedEarliest": "Recibido en Primer Lugar", + "invitationAccepted": "Invitación aceptada con éxito", + "invitationRejected": "Invitación rechazada con éxito", + "volunteerSuccess": "Solicitud de voluntariado realizada con éxito", + "recurring": "Recurrente", + "groupInvitationSubject": "Invitación a unirse al grupo de voluntarios", + "eventInvitationSubject": "Invitación a ser voluntario para el evento" } } diff --git a/public/locales/zh/common.json b/public/locales/zh/common.json index 7d47336692..e3da0bc32f 100644 --- a/public/locales/zh/common.json +++ b/public/locales/zh/common.json @@ -15,6 +15,7 @@ "login": "登录", "register": "登记", "menu": "菜单", + "gender": "性别", "settings": "设置", "users": "用户", "requests": "要求", diff --git a/public/locales/zh/errors.json b/public/locales/zh/errors.json index c872f367a5..c289d67aa1 100644 --- a/public/locales/zh/errors.json +++ b/public/locales/zh/errors.json @@ -7,5 +7,10 @@ "emailNotRegistered": "邮箱未注册", "notFoundMsg": "哎呀!", "errorOccurredCouldntCreate": "发生错误。 无法创建{{entity}}", - "errorLoading": "加载{{entity}}数据时出错" + "errorLoading": "加载{{entity}}数据时出错", + "invalidPhoneNumber": "请选择一个有效的电话号码", + "invalidEducationGrade": "请选择教育年级", + "invalidEmploymentStatus": "请选择有效的就业状况", + "invalidMaritalStatus": "请选择有效的婚姻状况", + "error400": "响应不成功. 从服务器收到状态代码 400" } diff --git a/public/locales/zh/translation.json b/public/locales/zh/translation.json index d5610594f6..32a4f953be 100644 --- a/public/locales/zh/translation.json +++ b/public/locales/zh/translation.json @@ -1,4 +1,16 @@ { + "leaderboard": { + "title": "排行榜", + "searchByVolunteer": "按志愿者搜索", + "mostHours": "最多时数", + "leastHours": "最少时数", + "timeFrame": "时间范围", + "allTime": "全部时间", + "weekly": "本周", + "monthly": "本月", + "yearly": "今年", + "noVolunteers": "未找到志愿者!" + }, "loginPage": { "title": "塔拉瓦管理员", "fromPalisadoes": "Palisadoes 基金会志愿者开发的开源应用程序", @@ -266,7 +278,9 @@ "members": "成员", "admins": "管理员", "requests": "请求", - "talawaApiUnavailable": "塔拉瓦 API 不可用" + "talawaApiUnavailable": "塔拉瓦 API 不可用", + "volunteerRankings": "志愿者排名", + "noVolunteers": "未找到志愿者!" }, "organizationPeople": { "title": "塔拉瓦会员", @@ -320,7 +334,8 @@ "noTagsFound": "未找到标签", "removeUserTag": "删除标签", "removeUserTagMessage": "您确定要删除此标签吗?", - "addChildTag": "添加子标签" + "addChildTag": "添加子标签", + "enterTagName": "输入标签名称" }, "manageTag": { "title": "标签详情", @@ -332,7 +347,34 @@ "successfullyUnassigned": "标签已从用户中取消分配", "addPeople": "添加人员", "add": "添加", - "subTags": "子标签" + "subTags": "子标签", + "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": "所有标签", + "noMoreMembersFound": "未找到更多成员" }, "userListCard": { "addAdmin": "添加管理员", @@ -365,6 +407,7 @@ "filterByTitle": "按标题过滤", "filterByLocation": "按地点过滤", "filterByDescription": "按描述过滤", + "searchMemberName": "搜索成员名称", "addEvent": "添加事件", "eventDetails": "活动详情", "eventTitle": "标题", @@ -396,53 +439,59 @@ "startDate": "开始日期", "endDate": "结束日期", "talawaApiUnavailable": "塔拉瓦 API 不可用", - "done": "完成" + "done": "完成", + "createChat": "创建聊天" }, "organizationActionItems": { - "actionItemCategory": "行动项目类别", - "actionItemDetails": "行动项目详情", - "actionItemCompleted": "行动项目已完成", - "assignee": "受让人", - "assigner": "转让人", + "actionItemCategory": "行动项类别", + "actionItemDetails": "行动项详情", + "actionItemCompleted": "行动项已完成", + "assignee": "受托人", + "assigner": "分配人", "assignmentDate": "分配日期", - "active": "积极的", + "active": "活跃", "clearFilters": "清除过滤器", "completionDate": "完成日期", - "createActionItem": "创建操作项", - "deleteActionItem": "删除操作项", - "deleteActionItemMsg": "您想删除此操作项吗?", - "details": "细节", - "dueDate": "到期日", + "createActionItem": "创建行动项", + "deleteActionItem": "删除行动项", + "deleteActionItemMsg": "是否要删除此行动项?", + "details": "详情", + "dueDate": "截止日期", "earliest": "最早", - "editActionItem": "编辑操作项", - "isCompleted": "完全的", - "latest": "最新的", - "makeActive": "积极的", - "noActionItems": "无行动项目", + "editActionItem": "编辑行动项", + "isCompleted": "已完成", + "latest": "最新", + "makeActive": "激活", + "noActionItems": "无行动项", "options": "选项", - "preCompletionNotes": "预完成注释", - "actionItemActive": "积极的", - "markCompletion": "标记完成", - "actionItemStatus": "行动项目状态", - "postCompletionNotes": "完成后注释", - "selectActionItemCategory": "选择操作项类别", + "preCompletionNotes": "预完成备注", + "actionItemActive": "活跃的行动项", + "markCompletion": "标记为完成", + "actionItemStatus": "行动项状态", + "postCompletionNotes": "完成后备注", + "selectActionItemCategory": "选择行动项类别", "selectAssignee": "选择受托人", - "status": "地位", - "successfulCreation": "操作项创建成功", - "successfulUpdation": "操作项已成功更新", - "successfulDeletion": "操作项已成功删除", - "title": "行动项目", + "status": "状态", + "successfulCreation": "行动项创建成功", + "successfulUpdation": "行动项更新成功", + "successfulDeletion": "行动项删除成功", + "title": "行动项", "category": "类别", - "allotedHours": "分配的小时", - "latestDueDate": "最晚到期日", - "earliestDueDate": "最早到期日", - "updateActionItem": "更新操作项", - "noneUpdated": "没有更新任何字段", - "updateStatusMsg": "您确定要将此操作项标记为待处理吗?", + "allottedHours": "分配的小时", + "latestDueDate": "最新截止日期", + "earliestDueDate": "最早截止日期", + "updateActionItem": "更新行动项", + "noneUpdated": "没有字段被更新", + "updateStatusMsg": "您确定要将此行动项标记为待处理吗?", "close": "关闭", - "eventActionItems": "活动行动项目", + "eventActionItems": "事件行动项", "no": "否", - "yes": "是" + "yes": "是", + "individuals": "个人", + "groups": "小组", + "assignTo": "分配给", + "volunteers": "志愿者", + "volunteerGroups": "志愿者小组" }, "organizationAgendaCategory": { "agendaCategoryDetails": "议程类别详情", @@ -531,7 +580,8 @@ "registerEvent": "注册活动", "close": "关闭", "talawaApiUnavailable": "塔拉瓦 API 不可用", - "done": "完成" + "done": "完成", + "createChat": "创建聊天" }, "funds": { "title": "基金", @@ -705,10 +755,12 @@ "title": "事件管理", "dashboard": "仪表板", "registrants": "注册者", - "eventActions": "事件动作", - "eventAgendas": "活动议程", - "eventStats": "事件统计", - "to": "到" + "attendance": "出席", + "actions": "操作", + "agendas": "议程", + "statistics": "统计数据", + "to": "到", + "volunteers": "志愿者" }, "forgotPassword": { "title": "塔拉瓦 忘记密码", @@ -865,6 +917,7 @@ "memberDetail": { "title": "用户详细信息", "addAdmin": "添加管理员", + "noeventsAttended": "未参加任何活动", "alreadyIsAdmin": "会员已经是管理员", "organizations": "组织机构", "events": "活动", @@ -884,6 +937,8 @@ "state": "状态", "city": "城市", "personalInfoHeading": "个人信息", + "viewAll": "查看全部", + "eventsAttended": "活动参与", "contactInfoHeading": "联系信息", "actionsHeading": "行动", "personalDetailsHeading": "个人资料详情", @@ -902,7 +957,12 @@ "delete": "删除", "saveChanges": "保存更改", "joined": "已加入", - "talawaApiUnavailable": "塔拉瓦 API 不可用" + "talawaApiUnavailable": "塔拉瓦 API 不可用", + "unassignUserTag": "取消分配标签", + "unassignUserTagMessage": "您想从此用户中删除标签吗?", + "successfullyUnassigned": "标签已从用户中取消分配", + "tagsAssigned": "已分配标签", + "noTagsAssigned": "未分配标签" }, "userLogin": { "login": "登录", @@ -1012,7 +1072,49 @@ "article": "文章", "postNowVisibleInFeed": "帖子现在在动态中可见" }, + "eventAttendance": { + "historical_statistics": "历史统计", + "Search member": "搜索成员", + "Member Name": "成员姓名", + "Status": "状态", + "Events Attended": "参加的活动", + "Task Assigned": "分配的任务", + "Member": "成员", + "Admin": "管理员", + "loading": "加载中...", + "noAttendees": "未找到参与者" + }, + "eventRegistrant": { + "sort": "排序", + "allRegistrants": "所有注册者", + "eventRegistrantsTable": "活动注册者表", + "serialNumber": "序列号", + "registrant": "注册者", + "registeredAt": "注册时间", + "createdAt": "创建时间", + "addRegistrant": "添加注册者", + "noRegistrantsFound": "未找到注册者" + }, + "onSpotAttendee": { + "title": "现场参与者", + "enterFirstName": "输入名字", + "enterLastName": "输入姓氏", + "enterEmail": "输入电子邮件", + "enterPhoneNo": "输入电话号码", + "selectGender": "选择性别", + "invalidDetailsMessage": "请填写所有必填字段", + "orgIdMissing": "组织ID缺失。请重试。", + "attendeeAddedSuccess": "参与者添加成功!", + "addAttendee": "添加", + "phoneNumber": "电话号码", + "addingAttendee": "添加中...", + "male": "男性", + "female": "女性", + "other": "其他" + }, "settings": { + "noeventsAttended": "未参加任何活动", + "eventAttended": "参加的活动", "profileSettings": "配置文件设置", "gender": "性别", "phoneNumber": "电话号码", @@ -1115,7 +1217,8 @@ "eventDescription": "活动描述", "eventLocation": "活动位置", "startDate": "开始日期", - "endDate": "结束日期" + "endDate": "结束日期", + "createChat": "创建聊天" }, "userEventCard": { "starts": "开始", @@ -1159,14 +1262,22 @@ "endOfResults": "结果结束" }, "userChat": { + "add": "添加", "chat": "聊天", "contacts": "联系方式", "search": "搜索", - "messages": "消息" + "messages": "消息", + "create": "创造", + "newChat": "新聊天", + "newGroupChat": "新群聊", + "groupInfo": "集团信息", + "members": "会员", + "addMembers": "Add Members" }, "userChatRoom": { "selectContact": "选择联系人开始对话", - "sendMessage": "发信息" + "sendMessage": "发信息", + "reply": "回复" }, "orgProfileField": { "loading": "加载中...", @@ -1315,5 +1426,83 @@ }, "userPledges": { "title": "我的承诺" + }, + "leaveOrganization": { + "title": "离开组织" + }, + "eventVolunteers": { + "volunteers": "志愿者", + "volunteer": "志愿者", + "volunteerGroups": "志愿者小组", + "individuals": "个人", + "groups": "小组", + "status": "状态", + "noVolunteers": "无志愿者", + "noVolunteerGroups": "无志愿者小组", + "add": "添加", + "mostHoursVolunteered": "最多志愿时数", + "leastHoursVolunteered": "最少志愿时数", + "accepted": "已接受", + "addVolunteer": "添加志愿者", + "removeVolunteer": "移除志愿者", + "volunteerAdded": "志愿者已成功添加", + "volunteerRemoved": "志愿者已成功移除", + "volunteerGroupCreated": "志愿者小组已成功创建", + "volunteerGroupUpdated": "志愿者小组已成功更新", + "volunteerGroupDeleted": "志愿者小组已成功删除", + "removeVolunteerMsg": "您确定要移除此志愿者吗?", + "deleteVolunteerGroupMsg": "您确定要删除此志愿者小组吗?", + "leader": "领导", + "group": "小组", + "createGroup": "创建小组", + "updateGroup": "更新小组", + "deleteGroup": "删除小组", + "volunteersRequired": "需要志愿者", + "volunteerDetails": "志愿者详情", + "hoursVolunteered": "志愿时数", + "groupDetails": "小组详情", + "creator": "创建者", + "requests": "请求", + "noRequests": "无请求", + "latest": "最新", + "earliest": "最早", + "requestAccepted": "请求已成功接受", + "requestRejected": "请求已成功拒绝", + "details": "详情", + "manageGroup": "管理小组", + "mostVolunteers": "最多的志愿者", + "leastVolunteers": "最少的志愿者" + }, + "userVolunteer": { + "title": "志愿服务", + "name": "标题", + "upcomingEvents": "即将举行的活动", + "requests": "请求", + "invitations": "邀请", + "groups": "志愿者小组", + "actions": "操作", + "searchByName": "按名称搜索", + "latestEndDate": "最晚结束日期", + "earliestEndDate": "最早结束日期", + "noEvents": "无即将举行的活动", + "volunteer": "志愿者", + "volunteered": "已志愿", + "join": "加入", + "joined": "已加入", + "searchByEventName": "按活动标题搜索", + "filter": "筛选", + "groupInvite": "小组邀请", + "individualInvite": "个人邀请", + "noInvitations": "无邀请", + "accept": "接受", + "reject": "拒绝", + "receivedLatest": "最近收到", + "receivedEarliest": "最早收到", + "invitationAccepted": "邀请已成功接受", + "invitationRejected": "邀请已成功拒绝", + "volunteerSuccess": "志愿请求成功", + "recurring": "重复", + "groupInvitationSubject": "邀请加入志愿者小组", + "eventInvitationSubject": "邀请参加活动志愿服务" } } diff --git a/schema.graphql b/schema.graphql index 9bfd49671c..a0ff7bde8b 100644 --- a/schema.graphql +++ b/schema.graphql @@ -214,25 +214,6 @@ type DeletePayload { success: Boolean! } -type DirectChat { - _id: ID! - createdAt: DateTime! - creator: User - messages: [DirectChatMessage] - updatedAt: DateTime! - users: [User!]! -} - -type DirectChatMessage { - _id: ID! - createdAt: DateTime! - directChatMessageBelongsTo: DirectChat! - messageContent: String! - receiver: User! - sender: User! - updatedAt: DateTime! -} - type Donation { _id: ID! amount: Float! @@ -470,26 +451,6 @@ type Group { updatedAt: DateTime! } -type GroupChat { - _id: ID! - title: String! - createdAt: DateTime! - creator: User - messages: [GroupChatMessage] - organization: Organization! - updatedAt: DateTime! - users: [User!]! -} - -type GroupChatMessage { - _id: ID! - createdAt: DateTime! - groupChatMessageBelongsTo: GroupChat! - messageContent: String! - sender: User! - updatedAt: DateTime! -} - type InvalidCursor implements FieldError { message: String! path: [String!]! @@ -579,31 +540,6 @@ type MembershipRequest { user: User! } -type Message { - _id: ID! - createdAt: DateTime! - creator: User - imageUrl: URL - text: String! - updatedAt: DateTime! - videoUrl: URL -} - -type MessageChat { - _id: ID! - createdAt: DateTime! - languageBarrier: Boolean - message: String! - receiver: User! - sender: User! - updatedAt: DateTime! -} - -input MessageChatInput { - message: String! - receiver: ID! -} - type MinimumLengthError implements FieldError { limit: Int! message: String! @@ -659,10 +595,8 @@ type Mutation { organizationId: ID! ): UserCustomData! addUserImage(file: String!): User! - addUserToGroupChat(chatId: ID!, userId: ID!): GroupChat! addUserToUserFamily(familyId: ID!, userId: ID!): UserFamily! adminRemoveEvent(eventId: ID!): Event! - adminRemoveGroup(groupId: ID!): GroupChat! assignUserTag(input: ToggleUserTagAssignInput!): User blockPluginCreationBySuperadmin( blockUser: Boolean! @@ -692,7 +626,6 @@ type Mutation { createAgendaCategory(input: CreateAgendaCategoryInput!): AgendaCategory! createComment(data: CommentInput!, postId: ID!): Comment createChat(data: chatInput!): Chat! - createDirectChat(data: createChatInput!): DirectChat! createDonation( amount: Float! nameOfOrg: String! @@ -706,9 +639,7 @@ type Mutation { recurrenceRuleData: RecurrenceRuleInput ): Event! createEventVolunteer(data: EventVolunteerInput!): EventVolunteer! - createGroupChat(data: createGroupChatInput!): GroupChat! createMember(input: UserAndOrganizationInput!): Organization! - createMessageChat(data: MessageChatInput!): MessageChat! createOrganization(data: OrganizationInput, file: String): Organization! createPlugin( pluginCreatedBy: String! @@ -743,11 +674,9 @@ type Mutation { removeAdmin(data: UserAndOrganizationInput!): AppUserProfile! removeAdvertisement(id: ID!): Advertisement removeComment(id: ID!): Comment - removeDirectChat(chatId: ID!, organizationId: ID!): DirectChat! removeEvent(id: ID!): Event! removeEventAttendee(data: EventAttendeeInput!): User! removeEventVolunteer(id: ID!): EventVolunteer! - removeGroupChat(chatId: ID!): GroupChat! removeMember(data: UserAndOrganizationInput!): Organization! removeOrganization(id: ID!): UserData! removeOrganizationCustomField( @@ -759,7 +688,6 @@ type Mutation { removeSampleOrganization: Boolean! removeUserCustomData(organizationId: ID!): UserCustomData! removeUserFamily(familyId: ID!): UserFamily! - removeUserFromGroupChat(chatId: ID!, userId: ID!): GroupChat! removeUserFromUserFamily(familyId: ID!, userId: ID!): UserFamily! removeUserImage: User! removeUserTag(id: ID!): UserTag @@ -767,14 +695,6 @@ type Mutation { saveFcmToken(token: String): Boolean! sendMembershipRequest(organizationId: ID!): MembershipRequest! sendMessageToChat(chatId: ID!, messageContent: String!, type: String!, replyTo: ID): ChatMessage! - sendMessageToDirectChat( - chatId: ID! - messageContent: String! - ): DirectChatMessage! - sendMessageToGroupChat( - chatId: ID! - messageContent: String! - ): GroupChatMessage! signUp(data: UserInput!, file: String): AuthData! togglePostPin(id: ID!, title: String): Post! unassignUserTag(input: ToggleUserTagAssignInput!): User @@ -1096,12 +1016,8 @@ type Query { 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 + eventsAttendedByUser(id: ID, orderBy: EventOrderByInput): [Event] eventVolunteersByEvent(id: ID!): [EventVolunteer] eventsByOrganization(id: ID, orderBy: EventOrderByInput): [Event] eventsByOrganizationConnection( @@ -1142,6 +1058,7 @@ type Query { where: UserWhereInput ): UserConnection! plugin(orgId: ID!): [Plugin] + getRecurringEvents(baseRecurringEventId: ID!): [Event] post(id: ID!): Post postsByOrganization(id: ID!, orderBy: PostOrderByInput): [Post] postsByOrganizationConnection( @@ -1195,10 +1112,7 @@ enum Status { } type Subscription { - directMessageChat: MessageChat messageSentToChat(userId: ID!): ChatMessage - messageSentToDirectChat(userId: ID!): DirectChatMessage - messageSentToGroupChat(userId: ID!): GroupChatMessage onPluginUpdate: Plugin } @@ -1397,6 +1311,7 @@ type User { phone: UserPhone pluginCreationAllowed: Boolean! registeredEvents: [Event] + eventsAttended: [Event] tagsAssignedWith( after: String before: String @@ -1592,17 +1507,6 @@ enum WeekDays { WE } -input createChatInput { - organizationId: ID - userIds: [ID!]! -} - -input createGroupChatInput { - organizationId: ID! - title: String! - userIds: [ID!]! -} - type Venue { _id: ID! capacity: Int! diff --git a/scripts/__mocks__/@dicebear/core.ts b/scripts/__mocks__/@dicebear/core.ts index 71a02f19ea..41811e2f8d 100644 --- a/scripts/__mocks__/@dicebear/core.ts +++ b/scripts/__mocks__/@dicebear/core.ts @@ -1,5 +1,5 @@ export const createAvatar = jest.fn(() => { return { - toDataUriSync: jest.fn(() => 'mocked-data-uri'), + toDataUri: jest.fn(() => 'mocked-data-uri'), }; }); diff --git a/scripts/__mocks__/@pdfme/generator.test.ts b/scripts/__mocks__/@pdfme/generator.test.ts new file mode 100644 index 0000000000..592c193a71 --- /dev/null +++ b/scripts/__mocks__/@pdfme/generator.test.ts @@ -0,0 +1,47 @@ +import { generate } from './generator'; +import type { Template } from '@pdfme/common'; + +describe('Testing mock generate util', () => { + test('should return a Promise', async () => { + const result = generate({ + template: { schemas: [] } as Template, + inputs: [], + }); + expect(result).toBeInstanceOf(Promise); + }); + + test('should resolve to a Uint8Array', async () => { + const result = generate({ + template: { schemas: [] } as Template, + inputs: [], + }); + expect(result).toBeInstanceOf(Uint8Array); + }); + + it('should throw an error when template is empty', async () => { + const emptyTemplate = { schemas: [] } as Template; + const validInputs = [{ field1: 'value1' }]; + + await expect( + generate({ template: emptyTemplate, inputs: validInputs }), + ).rejects.toThrow('Template or inputs cannot be empty.'); + }); + + it('should throw an error when inputs are empty', async () => { + const validTemplate = { schemas: [{ name: 'field1' }] } as Template; + const emptyInputs: Record[] = []; + + await expect( + generate({ template: validTemplate, inputs: emptyInputs }), + ).rejects.toThrow('Template or inputs cannot be empty.'); + }); + + it('should throw an error when both template and inputs are empty', async () => { + const emptyTemplate = { schemas: [] } as Template; + const emptyInputs: Record[] = []; + + await expect( + generate({ template: emptyTemplate, inputs: emptyInputs }), + ).rejects.toThrow('Template or inputs cannot be empty.'); + }); +}); diff --git a/scripts/__mocks__/@pdfme/generator.ts b/scripts/__mocks__/@pdfme/generator.ts new file mode 100644 index 0000000000..ac03ae6210 --- /dev/null +++ b/scripts/__mocks__/@pdfme/generator.ts @@ -0,0 +1,22 @@ +import type { Template } from '@pdfme/common'; + +export const generate = async ({ + template, + inputs, +}: { + template: Template; + inputs: Record[]; +}): Promise => { + if (template.schemas.length === 0 || inputs.length === 0) { + // console.log('pdf error: length : ', template, inputs, inputs.length); + throw new Error('Template or inputs cannot be empty.'); + } + // Generate mock PDF-like header bytes + const pdfHeader = [0x25, 0x50, 0x44, 0x46]; // %PDF + // Add some random content based on input size + const contentSize = Math.min(template.schemas.length, inputs.length) * 10; + const mockContent = Array.from({ length: contentSize }, () => + Math.floor(Math.random() * 256), + ); + return Promise.resolve(new Uint8Array([...pdfHeader, ...mockContent])); +}; diff --git a/setup.ts b/setup.ts index f930acc13a..2a6c437fa3 100644 --- a/setup.ts +++ b/setup.ts @@ -74,18 +74,26 @@ export async function main(): Promise { const url = new URL(endpoint); isConnected = await checkConnection(url.origin); } + const envPath = '.env'; + const currentEnvContent = fs.readFileSync(envPath, 'utf8'); + const talawaApiUrl = dotenv.parse(currentEnvContent).REACT_APP_TALAWA_URL; - const talawaApiUrl = dotenv.parse( - fs.readFileSync('.env'), - ).REACT_APP_TALAWA_URL; + const updatedEnvContent = currentEnvContent.replace( + `REACT_APP_TALAWA_URL=${talawaApiUrl}`, + `REACT_APP_TALAWA_URL=${endpoint}`, + ); - fs.readFile('.env', 'utf8', (err, data) => { - const result = data.replace( - `REACT_APP_TALAWA_URL=${talawaApiUrl}`, - `REACT_APP_TALAWA_URL=${endpoint}`, - ); - fs.writeFileSync('.env', result, 'utf8'); - }); + fs.writeFileSync(envPath, updatedEnvContent, 'utf8'); + const websocketUrl = endpoint.replace(/^http(s)?:\/\//, 'ws$1://'); + const currentWebSocketUrl = + dotenv.parse(updatedEnvContent).REACT_APP_BACKEND_WEBSOCKET_URL; + + const finalEnvContent = updatedEnvContent.replace( + `REACT_APP_BACKEND_WEBSOCKET_URL=${currentWebSocketUrl}`, + `REACT_APP_BACKEND_WEBSOCKET_URL=${websocketUrl}`, + ); + + fs.writeFileSync(envPath, finalEnvContent, 'utf8'); } const { shouldUseRecaptcha } = await inquirer.prompt({ diff --git a/src/App.tsx b/src/App.tsx index d6e825006f..069694592d 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -18,6 +18,7 @@ import OrganizationDashboard from 'screens/OrganizationDashboard/OrganizationDas import OrganizationEvents from 'screens/OrganizationEvents/OrganizationEvents'; import OrganizaitionFundCampiagn from 'screens/OrganizationFundCampaign/OrganizationFundCampagins'; import OrganizationFunds from 'screens/OrganizationFunds/OrganizationFunds'; +import FundCampaignPledge from 'screens/FundCampaignPledge/FundCampaignPledge'; import OrganizationPeople from 'screens/OrganizationPeople/OrganizationPeople'; import OrganizationTags from 'screens/OrganizationTags/OrganizationTags'; import ManageTag from 'screens/ManageTag/ManageTag'; @@ -27,6 +28,7 @@ import Requests from 'screens/Requests/Requests'; import Users from 'screens/Users/Users'; import CommunityProfile from 'screens/CommunityProfile/CommunityProfile'; import OrganizationVenues from 'screens/OrganizationVenues/OrganizationVenues'; +import Leaderboard from 'screens/Leaderboard/Leaderboard'; import React, { useEffect } from 'react'; // User Portal Components @@ -41,13 +43,14 @@ import { useQuery } from '@apollo/client'; import { CHECK_AUTH } from 'GraphQl/Queries/Queries'; import Advertisements from 'components/Advertisements/Advertisements'; import SecuredRouteForUser from 'components/UserPortal/SecuredRouteForUser/SecuredRouteForUser'; -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'; +import VolunteerManagement from 'screens/UserPortal/Volunteer/VolunteerManagement'; +import LeaveOrganization from 'screens/UserPortal/LeaveOrganization/LeaveOrganization'; const { setItem } = useLocalStorage(); @@ -148,10 +151,10 @@ function app(): JSX.Element { } /> } /> } /> - } /> + } /> } /> } /> } /> } /> } /> + } /> {extraRoutes} @@ -186,15 +190,24 @@ function app(): JSX.Element { }> } /> } /> - } /> + {/* } /> */} }> } /> } /> } /> } /> } /> + } /> } /> } /> + } + /> + } + /> }> code { color: inherit; } @@ -426,6 +458,7 @@ kbd { background-color: var(--bs-body-color); border-radius: 0.25rem; } + kbd kbd { padding: 0; font-size: 1em; @@ -503,6 +536,7 @@ select { select { word-wrap: normal; } + select:disabled { opacity: 1; } @@ -519,6 +553,7 @@ button, [type='submit'] { -webkit-appearance: button; } + button:not(:disabled), [type='button']:not(:disabled), [type='reset']:not(:disabled), @@ -550,11 +585,13 @@ legend { font-size: calc(1.275rem + 0.3vw); line-height: inherit; } + @media (min-width: 1200px) { legend { font-size: 1.5rem; } } + legend + * { clear: left; } @@ -630,6 +667,7 @@ progress { font-weight: 300; line-height: 1.2; } + @media (min-width: 1200px) { .display-1 { font-size: 5rem; @@ -641,6 +679,7 @@ progress { font-weight: 300; line-height: 1.2; } + @media (min-width: 1200px) { .display-2 { font-size: 4.5rem; @@ -652,6 +691,7 @@ progress { font-weight: 300; line-height: 1.2; } + @media (min-width: 1200px) { .display-3 { font-size: 4rem; @@ -663,6 +703,7 @@ progress { font-weight: 300; line-height: 1.2; } + @media (min-width: 1200px) { .display-4 { font-size: 3.5rem; @@ -674,6 +715,7 @@ progress { font-weight: 300; line-height: 1.2; } + @media (min-width: 1200px) { .display-5 { font-size: 3rem; @@ -685,6 +727,7 @@ progress { font-weight: 300; line-height: 1.2; } + @media (min-width: 1200px) { .display-6 { font-size: 2.5rem; @@ -704,6 +747,7 @@ progress { .list-inline-item { display: inline-block; } + .list-inline-item:not(:last-child) { margin-right: 0.5rem; } @@ -717,6 +761,7 @@ progress { margin-bottom: 1rem; font-size: 1.25rem; } + .blockquote > :last-child { margin-bottom: 0; } @@ -727,6 +772,7 @@ progress { font-size: 0.875em; color: #6c757d; } + .blockquote-footer::before { content: '— '; } @@ -781,6 +827,7 @@ progress { max-width: 540px; } } + @media (min-width: 768px) { .container-md, .container-sm, @@ -788,6 +835,7 @@ progress { max-width: 720px; } } + @media (min-width: 992px) { .container-lg, .container-md, @@ -796,6 +844,7 @@ progress { max-width: 960px; } } + @media (min-width: 1200px) { .container-xl, .container-lg, @@ -805,6 +854,7 @@ progress { max-width: 1140px; } } + @media (min-width: 1400px) { .container-xxl, .container-xl, @@ -815,6 +865,7 @@ progress { max-width: 1320px; } } + :root { --bs-breakpoint-xs: 0; --bs-breakpoint-sm: 576px; @@ -833,6 +884,7 @@ progress { margin-right: calc(-0.5 * var(--bs-gutter-x)); margin-left: calc(-0.5 * var(--bs-gutter-x)); } + .row > * { flex-shrink: 0; width: 100%; @@ -1054,847 +1106,1072 @@ progress { .col-sm { flex: 1 0 0%; } + .row-cols-sm-auto > * { flex: 0 0 auto; width: auto; } + .row-cols-sm-1 > * { flex: 0 0 auto; width: 100%; } + .row-cols-sm-2 > * { flex: 0 0 auto; width: 50%; } + .row-cols-sm-3 > * { flex: 0 0 auto; width: 33.3333333333%; } + .row-cols-sm-4 > * { flex: 0 0 auto; width: 25%; } + .row-cols-sm-5 > * { flex: 0 0 auto; width: 20%; } + .row-cols-sm-6 > * { flex: 0 0 auto; width: 16.6666666667%; } + .col-sm-auto { flex: 0 0 auto; width: auto; } + .col-sm-1 { flex: 0 0 auto; width: 8.33333333%; } + .col-sm-2 { flex: 0 0 auto; width: 16.66666667%; } + .col-sm-3 { flex: 0 0 auto; width: 25%; } + .col-sm-4 { flex: 0 0 auto; width: 33.33333333%; } + .col-sm-5 { flex: 0 0 auto; width: 41.66666667%; } + .col-sm-6 { flex: 0 0 auto; width: 50%; } + .col-sm-7 { flex: 0 0 auto; width: 58.33333333%; } + .col-sm-8 { flex: 0 0 auto; width: 66.66666667%; } + .col-sm-9 { flex: 0 0 auto; width: 75%; } + .col-sm-10 { flex: 0 0 auto; width: 83.33333333%; } + .col-sm-11 { flex: 0 0 auto; width: 91.66666667%; } + .col-sm-12 { flex: 0 0 auto; width: 100%; } + .offset-sm-0 { margin-left: 0; } + .offset-sm-1 { margin-left: 8.33333333%; } + .offset-sm-2 { margin-left: 16.66666667%; } + .offset-sm-3 { margin-left: 25%; } + .offset-sm-4 { margin-left: 33.33333333%; } + .offset-sm-5 { margin-left: 41.66666667%; } + .offset-sm-6 { margin-left: 50%; } + .offset-sm-7 { margin-left: 58.33333333%; } + .offset-sm-8 { margin-left: 66.66666667%; } + .offset-sm-9 { margin-left: 75%; } + .offset-sm-10 { margin-left: 83.33333333%; } + .offset-sm-11 { margin-left: 91.66666667%; } + .g-sm-0, .gx-sm-0 { --bs-gutter-x: 0; } + .g-sm-0, .gy-sm-0 { --bs-gutter-y: 0; } + .g-sm-1, .gx-sm-1 { --bs-gutter-x: 0.25rem; } + .g-sm-1, .gy-sm-1 { --bs-gutter-y: 0.25rem; } + .g-sm-2, .gx-sm-2 { --bs-gutter-x: 0.5rem; } + .g-sm-2, .gy-sm-2 { --bs-gutter-y: 0.5rem; } + .g-sm-3, .gx-sm-3 { --bs-gutter-x: 1rem; } + .g-sm-3, .gy-sm-3 { --bs-gutter-y: 1rem; } + .g-sm-4, .gx-sm-4 { --bs-gutter-x: 1.5rem; } + .g-sm-4, .gy-sm-4 { --bs-gutter-y: 1.5rem; } + .g-sm-5, .gx-sm-5 { --bs-gutter-x: 3rem; } + .g-sm-5, .gy-sm-5 { --bs-gutter-y: 3rem; } } + @media (min-width: 768px) { .col-md { flex: 1 0 0%; } + .row-cols-md-auto > * { flex: 0 0 auto; width: auto; } + .row-cols-md-1 > * { flex: 0 0 auto; width: 100%; } + .row-cols-md-2 > * { flex: 0 0 auto; width: 50%; } + .row-cols-md-3 > * { flex: 0 0 auto; width: 33.3333333333%; } + .row-cols-md-4 > * { flex: 0 0 auto; width: 25%; } + .row-cols-md-5 > * { flex: 0 0 auto; width: 20%; } + .row-cols-md-6 > * { flex: 0 0 auto; width: 16.6666666667%; } + .col-md-auto { flex: 0 0 auto; width: auto; } + .col-md-1 { flex: 0 0 auto; width: 8.33333333%; } + .col-md-2 { flex: 0 0 auto; width: 16.66666667%; } + .col-md-3 { flex: 0 0 auto; width: 25%; } + .col-md-4 { flex: 0 0 auto; width: 33.33333333%; } + .col-md-5 { flex: 0 0 auto; width: 41.66666667%; } + .col-md-6 { flex: 0 0 auto; width: 50%; } + .col-md-7 { flex: 0 0 auto; width: 58.33333333%; } + .col-md-8 { flex: 0 0 auto; width: 66.66666667%; } + .col-md-9 { flex: 0 0 auto; width: 75%; } + .col-md-10 { flex: 0 0 auto; width: 83.33333333%; } + .col-md-11 { flex: 0 0 auto; width: 91.66666667%; } + .col-md-12 { flex: 0 0 auto; width: 100%; } + .offset-md-0 { margin-left: 0; } + .offset-md-1 { margin-left: 8.33333333%; } + .offset-md-2 { margin-left: 16.66666667%; } + .offset-md-3 { margin-left: 25%; } + .offset-md-4 { margin-left: 33.33333333%; } + .offset-md-5 { margin-left: 41.66666667%; } + .offset-md-6 { margin-left: 50%; } + .offset-md-7 { margin-left: 58.33333333%; } + .offset-md-8 { margin-left: 66.66666667%; } + .offset-md-9 { margin-left: 75%; } + .offset-md-10 { margin-left: 83.33333333%; } + .offset-md-11 { margin-left: 91.66666667%; } + .g-md-0, .gx-md-0 { --bs-gutter-x: 0; } + .g-md-0, .gy-md-0 { --bs-gutter-y: 0; } + .g-md-1, .gx-md-1 { --bs-gutter-x: 0.25rem; } + .g-md-1, .gy-md-1 { --bs-gutter-y: 0.25rem; } + .g-md-2, .gx-md-2 { --bs-gutter-x: 0.5rem; } + .g-md-2, .gy-md-2 { --bs-gutter-y: 0.5rem; } + .g-md-3, .gx-md-3 { --bs-gutter-x: 1rem; } + .g-md-3, .gy-md-3 { --bs-gutter-y: 1rem; } + .g-md-4, .gx-md-4 { --bs-gutter-x: 1.5rem; } + .g-md-4, .gy-md-4 { --bs-gutter-y: 1.5rem; } + .g-md-5, .gx-md-5 { --bs-gutter-x: 3rem; } + .g-md-5, .gy-md-5 { --bs-gutter-y: 3rem; } } + @media (min-width: 992px) { .col-lg { flex: 1 0 0%; } + .row-cols-lg-auto > * { flex: 0 0 auto; width: auto; } + .row-cols-lg-1 > * { flex: 0 0 auto; width: 100%; } + .row-cols-lg-2 > * { flex: 0 0 auto; width: 50%; } + .row-cols-lg-3 > * { flex: 0 0 auto; width: 33.3333333333%; } + .row-cols-lg-4 > * { flex: 0 0 auto; width: 25%; } + .row-cols-lg-5 > * { flex: 0 0 auto; width: 20%; } + .row-cols-lg-6 > * { flex: 0 0 auto; width: 16.6666666667%; } + .col-lg-auto { flex: 0 0 auto; width: auto; } + .col-lg-1 { flex: 0 0 auto; width: 8.33333333%; } + .col-lg-2 { flex: 0 0 auto; width: 16.66666667%; } + .col-lg-3 { flex: 0 0 auto; width: 25%; } + .col-lg-4 { flex: 0 0 auto; width: 33.33333333%; } + .col-lg-5 { flex: 0 0 auto; width: 41.66666667%; } + .col-lg-6 { flex: 0 0 auto; width: 50%; } + .col-lg-7 { flex: 0 0 auto; width: 58.33333333%; } + .col-lg-8 { flex: 0 0 auto; width: 66.66666667%; } + .col-lg-9 { flex: 0 0 auto; width: 75%; } + .col-lg-10 { flex: 0 0 auto; width: 83.33333333%; } + .col-lg-11 { flex: 0 0 auto; width: 91.66666667%; } + .col-lg-12 { flex: 0 0 auto; width: 100%; } + .offset-lg-0 { margin-left: 0; } + .offset-lg-1 { margin-left: 8.33333333%; } + .offset-lg-2 { margin-left: 16.66666667%; } + .offset-lg-3 { margin-left: 25%; } + .offset-lg-4 { margin-left: 33.33333333%; } + .offset-lg-5 { margin-left: 41.66666667%; } + .offset-lg-6 { margin-left: 50%; } + .offset-lg-7 { margin-left: 58.33333333%; } + .offset-lg-8 { margin-left: 66.66666667%; } + .offset-lg-9 { margin-left: 75%; } + .offset-lg-10 { margin-left: 83.33333333%; } + .offset-lg-11 { margin-left: 91.66666667%; } + .g-lg-0, .gx-lg-0 { --bs-gutter-x: 0; } + .g-lg-0, .gy-lg-0 { --bs-gutter-y: 0; } + .g-lg-1, .gx-lg-1 { --bs-gutter-x: 0.25rem; } + .g-lg-1, .gy-lg-1 { --bs-gutter-y: 0.25rem; } + .g-lg-2, .gx-lg-2 { --bs-gutter-x: 0.5rem; } + .g-lg-2, .gy-lg-2 { --bs-gutter-y: 0.5rem; } + .g-lg-3, .gx-lg-3 { --bs-gutter-x: 1rem; } + .g-lg-3, .gy-lg-3 { --bs-gutter-y: 1rem; } + .g-lg-4, .gx-lg-4 { --bs-gutter-x: 1.5rem; } + .g-lg-4, .gy-lg-4 { --bs-gutter-y: 1.5rem; } + .g-lg-5, .gx-lg-5 { --bs-gutter-x: 3rem; } + .g-lg-5, .gy-lg-5 { --bs-gutter-y: 3rem; } } + @media (min-width: 1200px) { .col-xl { flex: 1 0 0%; } + .row-cols-xl-auto > * { flex: 0 0 auto; width: auto; } + .row-cols-xl-1 > * { flex: 0 0 auto; width: 100%; } + .row-cols-xl-2 > * { flex: 0 0 auto; width: 50%; } + .row-cols-xl-3 > * { flex: 0 0 auto; width: 33.3333333333%; } + .row-cols-xl-4 > * { flex: 0 0 auto; width: 25%; } + .row-cols-xl-5 > * { flex: 0 0 auto; width: 20%; } + .row-cols-xl-6 > * { flex: 0 0 auto; width: 16.6666666667%; } + .col-xl-auto { flex: 0 0 auto; width: auto; } + .col-xl-1 { flex: 0 0 auto; width: 8.33333333%; } + .col-xl-2 { flex: 0 0 auto; width: 16.66666667%; } + .col-xl-3 { flex: 0 0 auto; width: 25%; } + .col-xl-4 { flex: 0 0 auto; width: 33.33333333%; } + .col-xl-5 { flex: 0 0 auto; width: 41.66666667%; } + .col-xl-6 { flex: 0 0 auto; width: 50%; } + .col-xl-7 { flex: 0 0 auto; width: 58.33333333%; } + .col-xl-8 { flex: 0 0 auto; width: 66.66666667%; } + .col-xl-9 { flex: 0 0 auto; width: 75%; } + .col-xl-10 { flex: 0 0 auto; width: 83.33333333%; } + .col-xl-11 { flex: 0 0 auto; width: 91.66666667%; } + .col-xl-12 { flex: 0 0 auto; width: 100%; } + .offset-xl-0 { margin-left: 0; } + .offset-xl-1 { margin-left: 8.33333333%; } + .offset-xl-2 { margin-left: 16.66666667%; } + .offset-xl-3 { margin-left: 25%; } + .offset-xl-4 { margin-left: 33.33333333%; } + .offset-xl-5 { margin-left: 41.66666667%; } + .offset-xl-6 { margin-left: 50%; } + .offset-xl-7 { margin-left: 58.33333333%; } + .offset-xl-8 { margin-left: 66.66666667%; } + .offset-xl-9 { margin-left: 75%; } + .offset-xl-10 { margin-left: 83.33333333%; } + .offset-xl-11 { margin-left: 91.66666667%; } + .g-xl-0, .gx-xl-0 { --bs-gutter-x: 0; } + .g-xl-0, .gy-xl-0 { --bs-gutter-y: 0; } + .g-xl-1, .gx-xl-1 { --bs-gutter-x: 0.25rem; } + .g-xl-1, .gy-xl-1 { --bs-gutter-y: 0.25rem; } + .g-xl-2, .gx-xl-2 { --bs-gutter-x: 0.5rem; } + .g-xl-2, .gy-xl-2 { --bs-gutter-y: 0.5rem; } + .g-xl-3, .gx-xl-3 { --bs-gutter-x: 1rem; } + .g-xl-3, .gy-xl-3 { --bs-gutter-y: 1rem; } + .g-xl-4, .gx-xl-4 { --bs-gutter-x: 1.5rem; } + .g-xl-4, .gy-xl-4 { --bs-gutter-y: 1.5rem; } + .g-xl-5, .gx-xl-5 { --bs-gutter-x: 3rem; } + .g-xl-5, .gy-xl-5 { --bs-gutter-y: 3rem; } } + @media (min-width: 1400px) { .col-xxl { flex: 1 0 0%; } + .row-cols-xxl-auto > * { flex: 0 0 auto; width: auto; } + .row-cols-xxl-1 > * { flex: 0 0 auto; width: 100%; } + .row-cols-xxl-2 > * { flex: 0 0 auto; width: 50%; } + .row-cols-xxl-3 > * { flex: 0 0 auto; width: 33.3333333333%; } + .row-cols-xxl-4 > * { flex: 0 0 auto; width: 25%; } + .row-cols-xxl-5 > * { flex: 0 0 auto; width: 20%; } + .row-cols-xxl-6 > * { flex: 0 0 auto; width: 16.6666666667%; } + .col-xxl-auto { flex: 0 0 auto; width: auto; } + .col-xxl-1 { flex: 0 0 auto; width: 8.33333333%; } + .col-xxl-2 { flex: 0 0 auto; width: 16.66666667%; } + .col-xxl-3 { flex: 0 0 auto; width: 25%; } + .col-xxl-4 { flex: 0 0 auto; width: 33.33333333%; } + .col-xxl-5 { flex: 0 0 auto; width: 41.66666667%; } + .col-xxl-6 { flex: 0 0 auto; width: 50%; } + .col-xxl-7 { flex: 0 0 auto; width: 58.33333333%; } + .col-xxl-8 { flex: 0 0 auto; width: 66.66666667%; } + .col-xxl-9 { flex: 0 0 auto; width: 75%; } + .col-xxl-10 { flex: 0 0 auto; width: 83.33333333%; } + .col-xxl-11 { flex: 0 0 auto; width: 91.66666667%; } + .col-xxl-12 { flex: 0 0 auto; width: 100%; } + .offset-xxl-0 { margin-left: 0; } + .offset-xxl-1 { margin-left: 8.33333333%; } + .offset-xxl-2 { margin-left: 16.66666667%; } + .offset-xxl-3 { margin-left: 25%; } + .offset-xxl-4 { margin-left: 33.33333333%; } + .offset-xxl-5 { margin-left: 41.66666667%; } + .offset-xxl-6 { margin-left: 50%; } + .offset-xxl-7 { margin-left: 58.33333333%; } + .offset-xxl-8 { margin-left: 66.66666667%; } + .offset-xxl-9 { margin-left: 75%; } + .offset-xxl-10 { margin-left: 83.33333333%; } + .offset-xxl-11 { margin-left: 91.66666667%; } + .g-xxl-0, .gx-xxl-0 { --bs-gutter-x: 0; } + .g-xxl-0, .gy-xxl-0 { --bs-gutter-y: 0; } + .g-xxl-1, .gx-xxl-1 { --bs-gutter-x: 0.25rem; } + .g-xxl-1, .gy-xxl-1 { --bs-gutter-y: 0.25rem; } + .g-xxl-2, .gx-xxl-2 { --bs-gutter-x: 0.5rem; } + .g-xxl-2, .gy-xxl-2 { --bs-gutter-y: 0.5rem; } + .g-xxl-3, .gx-xxl-3 { --bs-gutter-x: 1rem; } + .g-xxl-3, .gy-xxl-3 { --bs-gutter-y: 1rem; } + .g-xxl-4, .gx-xxl-4 { --bs-gutter-x: 1.5rem; } + .g-xxl-4, .gy-xxl-4 { --bs-gutter-y: 1.5rem; } + .g-xxl-5, .gx-xxl-5 { --bs-gutter-x: 3rem; } + .g-xxl-5, .gy-xxl-5 { --bs-gutter-y: 3rem; } } + .table { --bs-table-color-type: initial; --bs-table-bg-type: initial; @@ -1915,6 +2192,7 @@ progress { vertical-align: top; border-color: var(--bs-table-border-color); } + .table > :not(caption) > * > * { padding: 0.5rem 0.5rem; color: var( @@ -1926,9 +2204,11 @@ progress { box-shadow: inset 0 0 0 9999px var(--bs-table-bg-state, var(--bs-table-bg-type, var(--bs-table-accent-bg))); } + .table > tbody { vertical-align: inherit; } + .table > thead { vertical-align: bottom; } @@ -1948,6 +2228,7 @@ progress { .table-bordered > :not(caption) > * { border-width: var(--bs-border-width) 0; } + .table-bordered > :not(caption) > * > * { border-width: 0 var(--bs-border-width); } @@ -1955,6 +2236,7 @@ progress { .table-borderless > :not(caption) > * > * { border-bottom-width: 0; } + .table-borderless > :not(:first-child) { border-top-width: 0; } @@ -2102,30 +2384,35 @@ progress { -webkit-overflow-scrolling: touch; } } + @media (max-width: 767.98px) { .table-responsive-md { overflow-x: auto; -webkit-overflow-scrolling: touch; } } + @media (max-width: 991.98px) { .table-responsive-lg { overflow-x: auto; -webkit-overflow-scrolling: touch; } } + @media (max-width: 1199.98px) { .table-responsive-xl { overflow-x: auto; -webkit-overflow-scrolling: touch; } } + @media (max-width: 1399.98px) { .table-responsive-xxl { overflow-x: auto; -webkit-overflow-scrolling: touch; } } + .form-label { margin-bottom: 0.5rem; } @@ -2173,17 +2460,21 @@ progress { border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; } + @media (prefers-reduced-motion: reduce) { .form-control { transition: none; } } + .form-control[type='file'] { overflow: hidden; } + .form-control[type='file']:not(:disabled):not([readonly]) { cursor: pointer; } + .form-control:focus { color: var(--bs-body-color); background-color: #f2f2f2; @@ -2191,23 +2482,28 @@ progress { outline: 0; box-shadow: 0 0 0 0.25rem rgba(49, 187, 107, 0.25); } + .form-control::-webkit-date-and-time-value { min-width: 85px; height: 1.5em; margin: 0; } + .form-control::-webkit-datetime-edit { display: block; padding: 0; } + .form-control::placeholder { color: var(--bs-secondary-color); opacity: 1; } + .form-control:disabled { background-color: var(--bs-secondary-bg); opacity: 1; } + .form-control::file-selector-button { padding: 0.7rem 1rem; margin: -0.7rem -1rem; @@ -2226,11 +2522,13 @@ progress { border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; } + @media (prefers-reduced-motion: reduce) { .form-control::file-selector-button { transition: none; } } + .form-control:hover:not(:disabled):not([readonly])::file-selector-button { background-color: var(--bs-secondary-bg); } @@ -2246,9 +2544,11 @@ progress { border: solid transparent; border-width: 0 0; } + .form-control-plaintext:focus { outline: 0; } + .form-control-plaintext.form-control-sm, .form-control-plaintext.form-control-lg { padding-right: 0; @@ -2261,6 +2561,7 @@ progress { font-size: 0.875rem; border-radius: var(--bs-border-radius-sm); } + .form-control-sm::file-selector-button { padding: 0.25rem 0.5rem; margin: -0.25rem -0.5rem; @@ -2273,6 +2574,7 @@ progress { font-size: 1.25rem; border-radius: var(--bs-border-radius-lg); } + .form-control-lg::file-selector-button { padding: 0.5rem 1rem; margin: -0.5rem -1rem; @@ -2282,9 +2584,11 @@ progress { textarea.form-control { min-height: calc(1.5em + 1.4rem + calc(0 * 2)); } + textarea.form-control-sm { min-height: calc(1.5em + 0.5rem + calc(0 * 2)); } + textarea.form-control-lg { min-height: calc(1.5em + 1rem + calc(0 * 2)); } @@ -2294,20 +2598,25 @@ textarea.form-control-lg { height: calc(1.5em + 1.4rem + calc(0 * 2)); padding: 0.7rem; } + .form-control-color:not(:disabled):not([readonly]) { cursor: pointer; } + .form-control-color::-moz-color-swatch { border: 0 !important; border-radius: var(--bs-border-radius); } + .form-control-color::-webkit-color-swatch { border: 0 !important; border-radius: var(--bs-border-radius); } + .form-control-color.form-control-sm { height: calc(1.5em + 0.5rem + calc(0 * 2)); } + .form-control-color.form-control-lg { height: calc(1.5em + 1rem + calc(0 * 2)); } @@ -2334,24 +2643,29 @@ textarea.form-control-lg { box-shadow 0.15s ease-in-out; appearance: none; } + @media (prefers-reduced-motion: reduce) { .form-select { transition: none; } } + .form-select:focus { border-color: #98ddb5; outline: 0; box-shadow: 0 0 0 0.25rem rgba(49, 187, 107, 0.25); } + .form-select[multiple], .form-select[size]:not([size='1']) { padding-right: 1rem; background-image: none; } + .form-select:disabled { background-color: var(--bs-secondary-bg); } + .form-select:-moz-focusring { color: transparent; text-shadow: 0 0 0 var(--bs-body-color); @@ -2383,6 +2697,7 @@ textarea.form-control-lg { padding-left: 1.5em; margin-bottom: 0.125rem; } + .form-check .form-check-input { float: left; margin-left: -1.5em; @@ -2393,6 +2708,7 @@ textarea.form-control-lg { padding-left: 0; text-align: right; } + .form-check-reverse .form-check-input { float: right; margin-right: -1.5em; @@ -2414,40 +2730,50 @@ textarea.form-control-lg { appearance: none; print-color-adjust: exact; } + .form-check-input[type='checkbox'] { border-radius: 0.25em; } + .form-check-input[type='radio'] { border-radius: 50%; } + .form-check-input:active { filter: brightness(90%); } + .form-check-input:focus { border-color: #98ddb5; outline: 0; box-shadow: 0 0 0 0.25rem rgba(49, 187, 107, 0.25); } + .form-check-input:checked { background-color: #31bb6b; border-color: #31bb6b; } + .form-check-input:checked[type='checkbox'] { --bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e"); } + .form-check-input:checked[type='radio'] { --bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e"); } + .form-check-input[type='checkbox']:indeterminate { background-color: #31bb6b; border-color: #31bb6b; --bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e"); } + .form-check-input:disabled { pointer-events: none; filter: none; opacity: 0.5; } + .form-check-input[disabled] ~ .form-check-label, .form-check-input:disabled ~ .form-check-label { cursor: default; @@ -2457,6 +2783,7 @@ textarea.form-control-lg { .form-switch { padding-left: 2.5em; } + .form-switch .form-check-input { --bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e"); width: 2em; @@ -2466,22 +2793,27 @@ textarea.form-control-lg { border-radius: 2em; transition: background-position 0.15s ease-in-out; } + @media (prefers-reduced-motion: reduce) { .form-switch .form-check-input { transition: none; } } + .form-switch .form-check-input:focus { --bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2398ddb5'/%3e%3c/svg%3e"); } + .form-switch .form-check-input:checked { background-position: right center; --bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e"); } + .form-switch.form-check-reverse { padding-right: 2.5em; padding-left: 0; } + .form-switch.form-check-reverse .form-check-input { margin-right: -2.5em; margin-left: 0; @@ -2497,6 +2829,7 @@ textarea.form-control-lg { clip: rect(0, 0, 0, 0); pointer-events: none; } + .btn-check[disabled] + .btn, .btn-check:disabled + .btn { pointer-events: none; @@ -2517,22 +2850,27 @@ textarea.form-control-lg { background-color: transparent; appearance: none; } + .form-range:focus { outline: 0; } + .form-range:focus::-webkit-slider-thumb { box-shadow: 0 0 0 1px #fff, 0 0 0 0.25rem rgba(49, 187, 107, 0.25); } + .form-range:focus::-moz-range-thumb { box-shadow: 0 0 0 1px #fff, 0 0 0 0.25rem rgba(49, 187, 107, 0.25); } + .form-range::-moz-focus-outer { border: 0; } + .form-range::-webkit-slider-thumb { width: 1rem; height: 1rem; @@ -2546,14 +2884,17 @@ textarea.form-control-lg { box-shadow 0.15s ease-in-out; appearance: none; } + @media (prefers-reduced-motion: reduce) { .form-range::-webkit-slider-thumb { transition: none; } } + .form-range::-webkit-slider-thumb:active { background-color: #c1ebd3; } + .form-range::-webkit-slider-runnable-track { width: 100%; height: 0.5rem; @@ -2563,6 +2904,7 @@ textarea.form-control-lg { border-color: transparent; border-radius: 1rem; } + .form-range::-moz-range-thumb { width: 1rem; height: 1rem; @@ -2575,14 +2917,17 @@ textarea.form-control-lg { box-shadow 0.15s ease-in-out; appearance: none; } + @media (prefers-reduced-motion: reduce) { .form-range::-moz-range-thumb { transition: none; } } + .form-range::-moz-range-thumb:active { background-color: #c1ebd3; } + .form-range::-moz-range-track { width: 100%; height: 0.5rem; @@ -2592,12 +2937,15 @@ textarea.form-control-lg { border-color: transparent; border-radius: 1rem; } + .form-range:disabled { pointer-events: none; } + .form-range:disabled::-webkit-slider-thumb { background-color: var(--bs-secondary-color); } + .form-range:disabled::-moz-range-thumb { background-color: var(--bs-secondary-color); } @@ -2605,6 +2953,7 @@ textarea.form-control-lg { .form-floating { position: relative; } + .form-floating > .form-control, .form-floating > .form-control-plaintext, .form-floating > .form-select { @@ -2612,6 +2961,7 @@ textarea.form-control-lg { min-height: calc(3.5rem + calc(0 * 2)); line-height: 1.25; } + .form-floating > label { position: absolute; top: 0; @@ -2630,19 +2980,23 @@ textarea.form-control-lg { opacity 0.1s ease-in-out, transform 0.1s ease-in-out; } + @media (prefers-reduced-motion: reduce) { .form-floating > label { transition: none; } } + .form-floating > .form-control, .form-floating > .form-control-plaintext { padding: 1rem 1rem; } + .form-floating > .form-control::placeholder, .form-floating > .form-control-plaintext::placeholder { color: transparent; } + .form-floating > .form-control:focus, .form-floating > .form-control:not(:placeholder-shown), .form-floating > .form-control-plaintext:focus, @@ -2650,15 +3004,18 @@ textarea.form-control-lg { padding-top: 1.625rem; padding-bottom: 0.625rem; } + .form-floating > .form-control:-webkit-autofill, .form-floating > .form-control-plaintext:-webkit-autofill { padding-top: 1.625rem; padding-bottom: 0.625rem; } + .form-floating > .form-select { padding-top: 1.625rem; padding-bottom: 0.625rem; } + .form-floating > .form-control:focus ~ label, .form-floating > .form-control:not(:placeholder-shown) ~ label, .form-floating > .form-control-plaintext ~ label, @@ -2666,6 +3023,7 @@ textarea.form-control-lg { color: rgba(var(--bs-body-color-rgb), 0.65); transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem); } + .form-floating > .form-control:focus ~ label::after, .form-floating > .form-control:not(:placeholder-shown) ~ label::after, .form-floating > .form-control-plaintext ~ label::after, @@ -2678,16 +3036,20 @@ textarea.form-control-lg { background-color: #f2f2f2; border-radius: var(--bs-border-radius); } + .form-floating > .form-control:-webkit-autofill ~ label { color: rgba(var(--bs-body-color-rgb), 0.65); transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem); } + .form-floating > .form-control-plaintext ~ label { border-width: 0 0; } + .form-floating > :disabled ~ label { color: #6c757d; } + .form-floating > :disabled ~ label::after { background-color: var(--bs-secondary-bg); } @@ -2699,6 +3061,7 @@ textarea.form-control-lg { align-items: stretch; width: 100%; } + .input-group > .form-control, .input-group > .form-select, .input-group > .form-floating { @@ -2707,15 +3070,18 @@ textarea.form-control-lg { width: 1%; min-width: 0; } + .input-group > .form-control:focus, .input-group > .form-select:focus, .input-group > .form-floating:focus-within { z-index: 5; } + .input-group .btn { position: relative; z-index: 2; } + .input-group .btn:focus { z-index: 5; } @@ -2772,6 +3138,7 @@ textarea.form-control-lg { border-top-right-radius: 0; border-bottom-right-radius: 0; } + .input-group.has-validation > :nth-last-child(n + 3):not(.dropdown-toggle):not(.dropdown-menu):not( .form-floating @@ -2786,6 +3153,7 @@ textarea.form-control-lg { border-top-right-radius: 0; border-bottom-right-radius: 0; } + .input-group > :not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not( .valid-feedback @@ -2794,6 +3162,7 @@ textarea.form-control-lg { border-top-left-radius: 0; border-bottom-left-radius: 0; } + .input-group > .form-floating:not(:first-child) > .form-control, .input-group > .form-floating:not(:first-child) > .form-select { border-top-left-radius: 0; @@ -2838,6 +3207,7 @@ textarea.form-control-lg { background-position: right calc(0.375em + 0.35rem) center; background-size: calc(0.75em + 0.7rem) calc(0.75em + 0.7rem); } + .was-validated .form-control:valid:focus, .form-control.is-valid:focus { border-color: var(--bs-form-valid-border-color); @@ -2854,6 +3224,7 @@ textarea.form-control.is-valid { .form-select.is-valid { border-color: var(--bs-form-valid-border-color); } + .was-validated .form-select:valid:not([multiple]):not([size]), .was-validated .form-select:valid:not([multiple])[size='1'], .form-select.is-valid:not([multiple]):not([size]), @@ -2867,6 +3238,7 @@ textarea.form-control.is-valid { 16px 12px, calc(0.75em + 0.7rem) calc(0.75em + 0.7rem); } + .was-validated .form-select:valid:focus, .form-select.is-valid:focus { border-color: var(--bs-form-valid-border-color); @@ -2882,14 +3254,17 @@ textarea.form-control.is-valid { .form-check-input.is-valid { border-color: var(--bs-form-valid-border-color); } + .was-validated .form-check-input:valid:checked, .form-check-input.is-valid:checked { background-color: var(--bs-form-valid-color); } + .was-validated .form-check-input:valid:focus, .form-check-input.is-valid:focus { box-shadow: 0 0 0 0.25rem rgba(var(--bs-success-rgb), 0.25); } + .was-validated .form-check-input:valid ~ .form-check-label, .form-check-input.is-valid ~ .form-check-label { color: var(--bs-form-valid-color); @@ -2946,6 +3321,7 @@ textarea.form-control.is-valid { background-position: right calc(0.375em + 0.35rem) center; background-size: calc(0.75em + 0.7rem) calc(0.75em + 0.7rem); } + .was-validated .form-control:invalid:focus, .form-control.is-invalid:focus { border-color: var(--bs-form-invalid-border-color); @@ -2962,6 +3338,7 @@ textarea.form-control.is-invalid { .form-select.is-invalid { border-color: var(--bs-form-invalid-border-color); } + .was-validated .form-select:invalid:not([multiple]):not([size]), .was-validated .form-select:invalid:not([multiple])[size='1'], .form-select.is-invalid:not([multiple]):not([size]), @@ -2975,6 +3352,7 @@ textarea.form-control.is-invalid { 16px 12px, calc(0.75em + 0.7rem) calc(0.75em + 0.7rem); } + .was-validated .form-select:invalid:focus, .form-select.is-invalid:focus { border-color: var(--bs-form-invalid-border-color); @@ -2990,14 +3368,17 @@ textarea.form-control.is-invalid { .form-check-input.is-invalid { border-color: var(--bs-form-invalid-border-color); } + .was-validated .form-check-input:invalid:checked, .form-check-input.is-invalid:checked { background-color: var(--bs-form-invalid-color); } + .was-validated .form-check-input:invalid:focus, .form-check-input.is-invalid:focus { box-shadow: 0 0 0 0.25rem rgba(var(--bs-danger-rgb), 0.25); } + .was-validated .form-check-input:invalid ~ .form-check-label, .form-check-input.is-invalid ~ .form-check-label { color: var(--bs-form-invalid-color); @@ -3054,21 +3435,25 @@ textarea.form-control.is-invalid { border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; } + @media (prefers-reduced-motion: reduce) { .btn { transition: none; } } + .btn:hover { color: var(--bs-btn-hover-color); background-color: var(--bs-btn-hover-bg); border-color: var(--bs-btn-hover-border-color); } + .btn-check + .btn:hover { color: var(--bs-btn-color); background-color: var(--bs-btn-bg); border-color: var(--bs-btn-border-color); } + .btn:focus-visible { color: var(--bs-btn-hover-color); background-color: var(--bs-btn-hover-bg); @@ -3076,11 +3461,13 @@ textarea.form-control.is-invalid { outline: 0; box-shadow: var(--bs-btn-focus-box-shadow); } + .btn-check:focus-visible + .btn { border-color: var(--bs-btn-hover-border-color); outline: 0; box-shadow: var(--bs-btn-focus-box-shadow); } + .btn-check:checked + .btn, :not(.btn-check) + .btn:active, .btn:first-child:active, @@ -3090,6 +3477,7 @@ textarea.form-control.is-invalid { background-color: var(--bs-btn-active-bg); border-color: var(--bs-btn-active-border-color); } + .btn-check:checked + .btn:focus-visible, :not(.btn-check) + .btn:active:focus-visible, .btn:first-child:active:focus-visible, @@ -3097,6 +3485,7 @@ textarea.form-control.is-invalid { .btn.show:focus-visible { box-shadow: var(--bs-btn-focus-box-shadow); } + .btn:disabled, .btn.disabled, fieldset:disabled .btn { @@ -3394,9 +3783,11 @@ fieldset:disabled .btn { --bs-btn-focus-shadow-rgb: 49, 132, 253; text-decoration: none; } + .btn-link:focus-visible { color: var(--bs-btn-color); } + .btn-link:hover { color: var(--bs-btn-hover-color); } @@ -3420,11 +3811,13 @@ fieldset:disabled .btn { .fade { transition: opacity 0.15s linear; } + @media (prefers-reduced-motion: reduce) { .fade { transition: none; } } + .fade:not(.show) { opacity: 0; } @@ -3438,16 +3831,19 @@ fieldset:disabled .btn { overflow: hidden; transition: height 0.35s ease; } + @media (prefers-reduced-motion: reduce) { .collapsing { transition: none; } } + .collapsing.collapse-horizontal { width: 0; height: auto; transition: width 0.35s ease; } + @media (prefers-reduced-motion: reduce) { .collapsing.collapse-horizontal { transition: none; @@ -3466,6 +3862,7 @@ fieldset:disabled .btn { .dropdown-toggle { white-space: nowrap; } + .dropdown-toggle::after { display: inline-block; margin-left: 0.255em; @@ -3476,6 +3873,7 @@ fieldset:disabled .btn { border-bottom: 0; border-left: 0.3em solid transparent; } + .dropdown-toggle:empty::after { margin-left: 0; } @@ -3524,6 +3922,7 @@ fieldset:disabled .btn { border: var(--bs-dropdown-border-width) solid var(--bs-dropdown-border-color); border-radius: var(--bs-dropdown-border-radius); } + .dropdown-menu[data-bs-popper] { top: 100%; left: 0; @@ -3533,6 +3932,7 @@ fieldset:disabled .btn { .dropdown-menu-start { --bs-position: start; } + .dropdown-menu-start[data-bs-popper] { right: auto; left: 0; @@ -3541,6 +3941,7 @@ fieldset:disabled .btn { .dropdown-menu-end { --bs-position: end; } + .dropdown-menu-end[data-bs-popper] { right: 0; left: auto; @@ -3550,88 +3951,109 @@ fieldset:disabled .btn { .dropdown-menu-sm-start { --bs-position: start; } + .dropdown-menu-sm-start[data-bs-popper] { right: auto; left: 0; } + .dropdown-menu-sm-end { --bs-position: end; } + .dropdown-menu-sm-end[data-bs-popper] { right: 0; left: auto; } } + @media (min-width: 768px) { .dropdown-menu-md-start { --bs-position: start; } + .dropdown-menu-md-start[data-bs-popper] { right: auto; left: 0; } + .dropdown-menu-md-end { --bs-position: end; } + .dropdown-menu-md-end[data-bs-popper] { right: 0; left: auto; } } + @media (min-width: 992px) { .dropdown-menu-lg-start { --bs-position: start; } + .dropdown-menu-lg-start[data-bs-popper] { right: auto; left: 0; } + .dropdown-menu-lg-end { --bs-position: end; } + .dropdown-menu-lg-end[data-bs-popper] { right: 0; left: auto; } } + @media (min-width: 1200px) { .dropdown-menu-xl-start { --bs-position: start; } + .dropdown-menu-xl-start[data-bs-popper] { right: auto; left: 0; } + .dropdown-menu-xl-end { --bs-position: end; } + .dropdown-menu-xl-end[data-bs-popper] { right: 0; left: auto; } } + @media (min-width: 1400px) { .dropdown-menu-xxl-start { --bs-position: start; } + .dropdown-menu-xxl-start[data-bs-popper] { right: auto; left: 0; } + .dropdown-menu-xxl-end { --bs-position: end; } + .dropdown-menu-xxl-end[data-bs-popper] { right: 0; left: auto; } } + .dropup .dropdown-menu[data-bs-popper] { top: auto; bottom: 100%; margin-top: 0; margin-bottom: var(--bs-dropdown-spacer); } + .dropup .dropdown-toggle::after { display: inline-block; margin-left: 0.255em; @@ -3642,6 +4064,7 @@ fieldset:disabled .btn { border-bottom: 0.3em solid; border-left: 0.3em solid transparent; } + .dropup .dropdown-toggle:empty::after { margin-left: 0; } @@ -3653,6 +4076,7 @@ fieldset:disabled .btn { margin-top: 0; margin-left: var(--bs-dropdown-spacer); } + .dropend .dropdown-toggle::after { display: inline-block; margin-left: 0.255em; @@ -3663,9 +4087,11 @@ fieldset:disabled .btn { border-bottom: 0.3em solid transparent; border-left: 0.3em solid; } + .dropend .dropdown-toggle:empty::after { margin-left: 0; } + .dropend .dropdown-toggle::after { vertical-align: 0; } @@ -3677,15 +4103,18 @@ fieldset:disabled .btn { margin-top: 0; margin-right: var(--bs-dropdown-spacer); } + .dropstart .dropdown-toggle::after { display: inline-block; margin-left: 0.255em; vertical-align: 0.255em; content: ''; } + .dropstart .dropdown-toggle::after { display: none; } + .dropstart .dropdown-toggle::before { display: inline-block; margin-right: 0.255em; @@ -3695,9 +4124,11 @@ fieldset:disabled .btn { border-right: 0.3em solid; border-bottom: 0.3em solid transparent; } + .dropstart .dropdown-toggle:empty::after { margin-left: 0; } + .dropstart .dropdown-toggle::before { vertical-align: 0; } @@ -3723,17 +4154,20 @@ fieldset:disabled .btn { border: 0; border-radius: var(--bs-dropdown-item-border-radius, 0); } + .dropdown-item:hover, .dropdown-item:focus { color: var(--bs-dropdown-link-hover-color); background-color: var(--bs-dropdown-link-hover-bg); } + .dropdown-item.active, .dropdown-item:active { color: var(--bs-dropdown-link-active-color); text-decoration: none; background-color: var(--bs-dropdown-link-active-bg); } + .dropdown-item.disabled, .dropdown-item:disabled { color: var(--bs-dropdown-link-disabled-color); @@ -3782,11 +4216,13 @@ fieldset:disabled .btn { display: inline-flex; vertical-align: middle; } + .btn-group > .btn, .btn-group-vertical > .btn { position: relative; flex: 1 1 auto; } + .btn-group > .btn-check:checked + .btn, .btn-group > .btn-check:focus + .btn, .btn-group > .btn:hover, @@ -3807,6 +4243,7 @@ fieldset:disabled .btn { flex-wrap: wrap; justify-content: flex-start; } + .btn-toolbar .input-group { width: auto; } @@ -3814,16 +4251,19 @@ fieldset:disabled .btn { .btn-group { border-radius: var(--bs-border-radius); } + .btn-group > :not(.btn-check:first-child) + .btn, .btn-group > .btn-group:not(:first-child) { margin-left: calc(var(--bs-border-width) * -1); } + .btn-group > .btn:not(:last-child):not(.dropdown-toggle), .btn-group > .btn.dropdown-toggle-split:first-child, .btn-group > .btn-group:not(:last-child) > .btn { border-top-right-radius: 0; border-bottom-right-radius: 0; } + .btn-group > .btn:nth-child(n + 3), .btn-group > :not(.btn-check) + .btn, .btn-group > .btn-group:not(:first-child) > .btn { @@ -3835,11 +4275,13 @@ fieldset:disabled .btn { padding-right: 0.75rem; padding-left: 0.75rem; } + .dropdown-toggle-split::after, .dropup .dropdown-toggle-split::after, .dropend .dropdown-toggle-split::after { margin-left: 0; } + .dropstart .dropdown-toggle-split::before { margin-right: 0; } @@ -3861,19 +4303,23 @@ fieldset:disabled .btn { align-items: flex-start; justify-content: center; } + .btn-group-vertical > .btn, .btn-group-vertical > .btn-group { width: 100%; } + .btn-group-vertical > .btn:not(:first-child), .btn-group-vertical > .btn-group:not(:first-child) { margin-top: calc(var(--bs-border-width) * -1); } + .btn-group-vertical > .btn:not(:last-child):not(.dropdown-toggle), .btn-group-vertical > .btn-group:not(:last-child) > .btn { border-bottom-right-radius: 0; border-bottom-left-radius: 0; } + .btn-group-vertical > .btn ~ .btn, .btn-group-vertical > .btn-group:not(:first-child) > .btn { border-top-left-radius: 0; @@ -3907,19 +4353,23 @@ fieldset:disabled .btn { background-color 0.15s ease-in-out, border-color 0.15s ease-in-out; } + @media (prefers-reduced-motion: reduce) { .nav-link { transition: none; } } + .nav-link:hover, .nav-link:focus { color: var(--bs-nav-link-hover-color); } + .nav-link:focus-visible { outline: 0; box-shadow: 0 0 0 0.25rem rgba(49, 187, 107, 0.25); } + .nav-link.disabled { color: var(--bs-nav-link-disabled-color); pointer-events: none; @@ -3939,29 +4389,34 @@ fieldset:disabled .btn { border-bottom: var(--bs-nav-tabs-border-width) solid var(--bs-nav-tabs-border-color); } + .nav-tabs .nav-link { margin-bottom: calc(-1 * var(--bs-nav-tabs-border-width)); border: var(--bs-nav-tabs-border-width) solid transparent; border-top-left-radius: var(--bs-nav-tabs-border-radius); border-top-right-radius: var(--bs-nav-tabs-border-radius); } + .nav-tabs .nav-link:hover, .nav-tabs .nav-link:focus { isolation: isolate; border-color: var(--bs-nav-tabs-link-hover-border-color); } + .nav-tabs .nav-link.disabled, .nav-tabs .nav-link:disabled { color: var(--bs-nav-link-disabled-color); background-color: transparent; border-color: transparent; } + .nav-tabs .nav-link.active, .nav-tabs .nav-item.show .nav-link { color: var(--bs-nav-tabs-link-active-color); background-color: var(--bs-nav-tabs-link-active-bg); border-color: var(--bs-nav-tabs-link-active-border-color); } + .nav-tabs .dropdown-menu { margin-top: calc(-1 * var(--bs-nav-tabs-border-width)); border-top-left-radius: 0; @@ -3973,14 +4428,17 @@ fieldset:disabled .btn { --bs-nav-pills-link-active-color: #fff; --bs-nav-pills-link-active-bg: #31bb6b; } + .nav-pills .nav-link { border-radius: var(--bs-nav-pills-border-radius); } + .nav-pills .nav-link:disabled { color: var(--bs-nav-link-disabled-color); background-color: transparent; border-color: transparent; } + .nav-pills .nav-link.active, .nav-pills .show > .nav-link { color: var(--bs-nav-pills-link-active-color); @@ -3993,15 +4451,18 @@ fieldset:disabled .btn { --bs-nav-underline-link-active-color: var(--bs-emphasis-color); gap: var(--bs-nav-underline-gap); } + .nav-underline .nav-link { padding-right: 0; padding-left: 0; border-bottom: var(--bs-nav-underline-border-width) solid transparent; } + .nav-underline .nav-link:hover, .nav-underline .nav-link:focus { border-bottom-color: currentcolor; } + .nav-underline .nav-link.active, .nav-underline .show > .nav-link { font-weight: 700; @@ -4030,6 +4491,7 @@ fieldset:disabled .btn { .tab-content > .tab-pane { display: none; } + .tab-content > .active { display: block; } @@ -4062,6 +4524,7 @@ fieldset:disabled .btn { justify-content: space-between; padding: var(--bs-navbar-padding-y) var(--bs-navbar-padding-x); } + .navbar > .container, .navbar > .container-fluid, .navbar > .container-sm, @@ -4074,6 +4537,7 @@ fieldset:disabled .btn { align-items: center; justify-content: space-between; } + .navbar-brand { padding-top: var(--bs-navbar-brand-padding-y); padding-bottom: var(--bs-navbar-brand-padding-y); @@ -4082,6 +4546,7 @@ fieldset:disabled .btn { color: var(--bs-navbar-brand-color); white-space: nowrap; } + .navbar-brand:hover, .navbar-brand:focus { color: var(--bs-navbar-brand-hover-color); @@ -4100,10 +4565,12 @@ fieldset:disabled .btn { margin-bottom: 0; list-style: none; } + .navbar-nav .nav-link.active, .navbar-nav .nav-link.show { color: var(--bs-navbar-active-color); } + .navbar-nav .dropdown-menu { position: static; } @@ -4113,6 +4580,7 @@ fieldset:disabled .btn { padding-bottom: 0.5rem; color: var(--bs-navbar-color); } + .navbar-text a, .navbar-text a:hover, .navbar-text a:focus { @@ -4135,14 +4603,17 @@ fieldset:disabled .btn { border-radius: var(--bs-navbar-toggler-border-radius); transition: var(--bs-navbar-toggler-transition); } + @media (prefers-reduced-motion: reduce) { .navbar-toggler { transition: none; } } + .navbar-toggler:hover { text-decoration: none; } + .navbar-toggler:focus { text-decoration: none; outline: 0; @@ -4170,26 +4641,33 @@ fieldset:disabled .btn { flex-wrap: nowrap; justify-content: flex-start; } + .navbar-expand-sm .navbar-nav { flex-direction: row; } + .navbar-expand-sm .navbar-nav .dropdown-menu { position: absolute; } + .navbar-expand-sm .navbar-nav .nav-link { padding-right: var(--bs-navbar-nav-link-padding-x); padding-left: var(--bs-navbar-nav-link-padding-x); } + .navbar-expand-sm .navbar-nav-scroll { overflow: visible; } + .navbar-expand-sm .navbar-collapse { display: flex !important; flex-basis: auto; } + .navbar-expand-sm .navbar-toggler { display: none; } + .navbar-expand-sm .offcanvas { position: static; z-index: auto; @@ -4202,9 +4680,11 @@ fieldset:disabled .btn { transform: none !important; transition: none; } + .navbar-expand-sm .offcanvas .offcanvas-header { display: none; } + .navbar-expand-sm .offcanvas .offcanvas-body { display: flex; flex-grow: 0; @@ -4212,31 +4692,39 @@ fieldset:disabled .btn { overflow-y: visible; } } + @media (min-width: 768px) { .navbar-expand-md { flex-wrap: nowrap; justify-content: flex-start; } + .navbar-expand-md .navbar-nav { flex-direction: row; } + .navbar-expand-md .navbar-nav .dropdown-menu { position: absolute; } + .navbar-expand-md .navbar-nav .nav-link { padding-right: var(--bs-navbar-nav-link-padding-x); padding-left: var(--bs-navbar-nav-link-padding-x); } + .navbar-expand-md .navbar-nav-scroll { overflow: visible; } + .navbar-expand-md .navbar-collapse { display: flex !important; flex-basis: auto; } + .navbar-expand-md .navbar-toggler { display: none; } + .navbar-expand-md .offcanvas { position: static; z-index: auto; @@ -4249,9 +4737,11 @@ fieldset:disabled .btn { transform: none !important; transition: none; } + .navbar-expand-md .offcanvas .offcanvas-header { display: none; } + .navbar-expand-md .offcanvas .offcanvas-body { display: flex; flex-grow: 0; @@ -4259,31 +4749,39 @@ fieldset:disabled .btn { overflow-y: visible; } } + @media (min-width: 992px) { .navbar-expand-lg { flex-wrap: nowrap; justify-content: flex-start; } + .navbar-expand-lg .navbar-nav { flex-direction: row; } + .navbar-expand-lg .navbar-nav .dropdown-menu { position: absolute; } + .navbar-expand-lg .navbar-nav .nav-link { padding-right: var(--bs-navbar-nav-link-padding-x); padding-left: var(--bs-navbar-nav-link-padding-x); } + .navbar-expand-lg .navbar-nav-scroll { overflow: visible; } + .navbar-expand-lg .navbar-collapse { display: flex !important; flex-basis: auto; } + .navbar-expand-lg .navbar-toggler { display: none; } + .navbar-expand-lg .offcanvas { position: static; z-index: auto; @@ -4296,9 +4794,11 @@ fieldset:disabled .btn { transform: none !important; transition: none; } + .navbar-expand-lg .offcanvas .offcanvas-header { display: none; } + .navbar-expand-lg .offcanvas .offcanvas-body { display: flex; flex-grow: 0; @@ -4306,31 +4806,39 @@ fieldset:disabled .btn { overflow-y: visible; } } + @media (min-width: 1200px) { .navbar-expand-xl { flex-wrap: nowrap; justify-content: flex-start; } + .navbar-expand-xl .navbar-nav { flex-direction: row; } + .navbar-expand-xl .navbar-nav .dropdown-menu { position: absolute; } + .navbar-expand-xl .navbar-nav .nav-link { padding-right: var(--bs-navbar-nav-link-padding-x); padding-left: var(--bs-navbar-nav-link-padding-x); } + .navbar-expand-xl .navbar-nav-scroll { overflow: visible; } + .navbar-expand-xl .navbar-collapse { display: flex !important; flex-basis: auto; } + .navbar-expand-xl .navbar-toggler { display: none; } + .navbar-expand-xl .offcanvas { position: static; z-index: auto; @@ -4343,9 +4851,11 @@ fieldset:disabled .btn { transform: none !important; transition: none; } + .navbar-expand-xl .offcanvas .offcanvas-header { display: none; } + .navbar-expand-xl .offcanvas .offcanvas-body { display: flex; flex-grow: 0; @@ -4353,31 +4863,39 @@ fieldset:disabled .btn { overflow-y: visible; } } + @media (min-width: 1400px) { .navbar-expand-xxl { flex-wrap: nowrap; justify-content: flex-start; } + .navbar-expand-xxl .navbar-nav { flex-direction: row; } + .navbar-expand-xxl .navbar-nav .dropdown-menu { position: absolute; } + .navbar-expand-xxl .navbar-nav .nav-link { padding-right: var(--bs-navbar-nav-link-padding-x); padding-left: var(--bs-navbar-nav-link-padding-x); } + .navbar-expand-xxl .navbar-nav-scroll { overflow: visible; } + .navbar-expand-xxl .navbar-collapse { display: flex !important; flex-basis: auto; } + .navbar-expand-xxl .navbar-toggler { display: none; } + .navbar-expand-xxl .offcanvas { position: static; z-index: auto; @@ -4390,9 +4908,11 @@ fieldset:disabled .btn { transform: none !important; transition: none; } + .navbar-expand-xxl .offcanvas .offcanvas-header { display: none; } + .navbar-expand-xxl .offcanvas .offcanvas-body { display: flex; flex-grow: 0; @@ -4400,30 +4920,38 @@ fieldset:disabled .btn { overflow-y: visible; } } + .navbar-expand { flex-wrap: nowrap; justify-content: flex-start; } + .navbar-expand .navbar-nav { flex-direction: row; } + .navbar-expand .navbar-nav .dropdown-menu { position: absolute; } + .navbar-expand .navbar-nav .nav-link { padding-right: var(--bs-navbar-nav-link-padding-x); padding-left: var(--bs-navbar-nav-link-padding-x); } + .navbar-expand .navbar-nav-scroll { overflow: visible; } + .navbar-expand .navbar-collapse { display: flex !important; flex-basis: auto; } + .navbar-expand .navbar-toggler { display: none; } + .navbar-expand .offcanvas { position: static; z-index: auto; @@ -4436,9 +4964,11 @@ fieldset:disabled .btn { transform: none !important; transition: none; } + .navbar-expand .offcanvas .offcanvas-header { display: none; } + .navbar-expand .offcanvas .offcanvas-body { display: flex; flex-grow: 0; @@ -4496,24 +5026,29 @@ fieldset:disabled .btn { border: var(--bs-card-border-width) solid var(--bs-card-border-color); border-radius: var(--bs-card-border-radius); } + .card > hr { margin-right: 0; margin-left: 0; } + .card > .list-group { border-top: inherit; border-bottom: inherit; } + .card > .list-group:first-child { border-top-width: 0; border-top-left-radius: var(--bs-card-inner-border-radius); border-top-right-radius: var(--bs-card-inner-border-radius); } + .card > .list-group:last-child { border-bottom-width: 0; border-bottom-right-radius: var(--bs-card-inner-border-radius); border-bottom-left-radius: var(--bs-card-inner-border-radius); } + .card > .card-header + .list-group, .card > .list-group + .card-footer { border-top: 0; @@ -4551,6 +5086,7 @@ fieldset:disabled .btn { background-color: var(--bs-card-cap-bg); border-bottom: var(--bs-card-border-width) solid var(--bs-card-border-color); } + .card-header:first-child { border-radius: var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius) 0 0; @@ -4562,6 +5098,7 @@ fieldset:disabled .btn { background-color: var(--bs-card-cap-bg); border-top: var(--bs-card-border-width) solid var(--bs-card-border-color); } + .card-footer:last-child { border-radius: 0 0 var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius); @@ -4573,6 +5110,7 @@ fieldset:disabled .btn { margin-left: calc(-0.5 * var(--bs-card-cap-padding-x)); border-bottom: 0; } + .card-header-tabs .nav-link.active { background-color: var(--bs-card-bg); border-bottom-color: var(--bs-card-bg); @@ -4614,39 +5152,48 @@ fieldset:disabled .btn { .card-group > .card { margin-bottom: var(--bs-card-group-margin); } + @media (min-width: 576px) { .card-group { display: flex; flex-flow: row wrap; } + .card-group > .card { flex: 1 0 0%; margin-bottom: 0; } + .card-group > .card + .card { margin-left: 0; border-left: 0; } + .card-group > .card:not(:last-child) { border-top-right-radius: 0; border-bottom-right-radius: 0; } + .card-group > .card:not(:last-child) .card-img-top, .card-group > .card:not(:last-child) .card-header { border-top-right-radius: 0; } + .card-group > .card:not(:last-child) .card-img-bottom, .card-group > .card:not(:last-child) .card-footer { border-bottom-right-radius: 0; } + .card-group > .card:not(:first-child) { border-top-left-radius: 0; border-bottom-left-radius: 0; } + .card-group > .card:not(:first-child) .card-img-top, .card-group > .card:not(:first-child) .card-header { border-top-left-radius: 0; } + .card-group > .card:not(:first-child) .card-img-bottom, .card-group > .card:not(:first-child) .card-footer { border-bottom-left-radius: 0; @@ -4697,21 +5244,25 @@ fieldset:disabled .btn { overflow-anchor: none; transition: var(--bs-accordion-transition); } + @media (prefers-reduced-motion: reduce) { .accordion-button { transition: none; } } + .accordion-button:not(.collapsed) { color: var(--bs-accordion-active-color); background-color: var(--bs-accordion-active-bg); box-shadow: inset 0 calc(-1 * var(--bs-accordion-border-width)) 0 var(--bs-accordion-border-color); } + .accordion-button:not(.collapsed)::after { background-image: var(--bs-accordion-btn-active-icon); transform: var(--bs-accordion-btn-icon-transform); } + .accordion-button::after { flex-shrink: 0; width: var(--bs-accordion-btn-icon-width); @@ -4723,14 +5274,17 @@ fieldset:disabled .btn { background-size: var(--bs-accordion-btn-icon-width); transition: var(--bs-accordion-btn-icon-transition); } + @media (prefers-reduced-motion: reduce) { .accordion-button::after { transition: none; } } + .accordion-button:hover { z-index: 2; } + .accordion-button:focus { z-index: 3; border-color: var(--bs-accordion-btn-focus-border-color); @@ -4748,25 +5302,31 @@ fieldset:disabled .btn { border: var(--bs-accordion-border-width) solid var(--bs-accordion-border-color); } + .accordion-item:first-of-type { border-top-left-radius: var(--bs-accordion-border-radius); border-top-right-radius: var(--bs-accordion-border-radius); } + .accordion-item:first-of-type .accordion-button { border-top-left-radius: var(--bs-accordion-inner-border-radius); border-top-right-radius: var(--bs-accordion-inner-border-radius); } + .accordion-item:not(:first-of-type) { border-top: 0; } + .accordion-item:last-of-type { border-bottom-right-radius: var(--bs-accordion-border-radius); border-bottom-left-radius: var(--bs-accordion-border-radius); } + .accordion-item:last-of-type .accordion-button.collapsed { border-bottom-right-radius: var(--bs-accordion-inner-border-radius); border-bottom-left-radius: var(--bs-accordion-inner-border-radius); } + .accordion-item:last-of-type .accordion-collapse { border-bottom-right-radius: var(--bs-accordion-border-radius); border-bottom-left-radius: var(--bs-accordion-border-radius); @@ -4779,17 +5339,21 @@ fieldset:disabled .btn { .accordion-flush .accordion-collapse { border-width: 0; } + .accordion-flush .accordion-item { border-right: 0; border-left: 0; border-radius: 0; } + .accordion-flush .accordion-item:first-child { border-top: 0; } + .accordion-flush .accordion-item:last-child { border-bottom: 0; } + .accordion-flush .accordion-item .accordion-button, .accordion-flush .accordion-item .accordion-button.collapsed { border-radius: 0; @@ -4822,6 +5386,7 @@ fieldset:disabled .btn { .breadcrumb-item + .breadcrumb-item { padding-left: var(--bs-breadcrumb-item-padding-x); } + .breadcrumb-item + .breadcrumb-item::before { float: left; padding-right: var(--bs-breadcrumb-item-padding-x); @@ -4829,6 +5394,7 @@ fieldset:disabled .btn { content: var(--bs-breadcrumb-divider, '/') /* rtl: var(--bs-breadcrumb-divider, "/") */; } + .breadcrumb-item.active { color: var(--bs-breadcrumb-item-active-color); } @@ -4874,17 +5440,20 @@ fieldset:disabled .btn { border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; } + @media (prefers-reduced-motion: reduce) { .page-link { transition: none; } } + .page-link:hover { z-index: 2; color: var(--bs-pagination-hover-color); background-color: var(--bs-pagination-hover-bg); border-color: var(--bs-pagination-hover-border-color); } + .page-link:focus { z-index: 3; color: var(--bs-pagination-focus-color); @@ -4892,6 +5461,7 @@ fieldset:disabled .btn { outline: 0; box-shadow: var(--bs-pagination-focus-box-shadow); } + .page-link.active, .active > .page-link { z-index: 3; @@ -4899,6 +5469,7 @@ fieldset:disabled .btn { background-color: var(--bs-pagination-active-bg); border-color: var(--bs-pagination-active-border-color); } + .page-link.disabled, .disabled > .page-link { color: var(--bs-pagination-disabled-color); @@ -4910,10 +5481,12 @@ fieldset:disabled .btn { .page-item:not(:first-child) .page-link { margin-left: calc(var(--bs-border-width) * -1); } + .page-item:first-child .page-link { border-top-left-radius: var(--bs-pagination-border-radius); border-bottom-left-radius: var(--bs-pagination-border-radius); } + .page-item:last-child .page-link { border-top-right-radius: var(--bs-pagination-border-radius); border-bottom-right-radius: var(--bs-pagination-border-radius); @@ -4951,6 +5524,7 @@ fieldset:disabled .btn { vertical-align: baseline; border-radius: var(--bs-badge-border-radius); } + .badge:empty { display: none; } @@ -4991,6 +5565,7 @@ fieldset:disabled .btn { .alert-dismissible { padding-right: 3rem; } + .alert-dismissible .btn-close { position: absolute; top: 0; @@ -5060,6 +5635,7 @@ fieldset:disabled .btn { background-position-x: 1rem; } } + .progress, .progress-stacked { --bs-progress-height: 1rem; @@ -5089,6 +5665,7 @@ fieldset:disabled .btn { background-color: var(--bs-progress-bar-bg); transition: var(--bs-progress-bar-transition); } + @media (prefers-reduced-motion: reduce) { .progress-bar { transition: none; @@ -5120,6 +5697,7 @@ fieldset:disabled .btn { .progress-bar-animated { animation: 1s linear infinite progress-bar-stripes; } + @media (prefers-reduced-motion: reduce) { .progress-bar-animated { animation: none; @@ -5155,6 +5733,7 @@ fieldset:disabled .btn { list-style-type: none; counter-reset: section; } + .list-group-numbered > .list-group-item::before { content: counters(section, '.') '. '; counter-increment: section; @@ -5165,6 +5744,7 @@ fieldset:disabled .btn { color: var(--bs-list-group-action-color); text-align: inherit; } + .list-group-item-action:hover, .list-group-item-action:focus { z-index: 1; @@ -5172,6 +5752,7 @@ fieldset:disabled .btn { text-decoration: none; background-color: var(--bs-list-group-action-hover-bg); } + .list-group-item-action:active { color: var(--bs-list-group-action-active-color); background-color: var(--bs-list-group-action-active-bg); @@ -5187,29 +5768,35 @@ fieldset:disabled .btn { border: var(--bs-list-group-border-width) solid var(--bs-list-group-border-color); } + .list-group-item:first-child { border-top-left-radius: inherit; border-top-right-radius: inherit; } + .list-group-item:last-child { border-bottom-right-radius: inherit; border-bottom-left-radius: inherit; } + .list-group-item.disabled, .list-group-item:disabled { color: var(--bs-list-group-disabled-color); pointer-events: none; background-color: var(--bs-list-group-disabled-bg); } + .list-group-item.active { z-index: 2; color: var(--bs-list-group-active-color); background-color: var(--bs-list-group-active-bg); border-color: var(--bs-list-group-active-border-color); } + .list-group-item + .list-group-item { border-top-width: 0; } + .list-group-item + .list-group-item.active { margin-top: calc(-1 * var(--bs-list-group-border-width)); border-top-width: var(--bs-list-group-border-width); @@ -5218,21 +5805,26 @@ fieldset:disabled .btn { .list-group-horizontal { flex-direction: row; } + .list-group-horizontal > .list-group-item:first-child:not(:last-child) { border-bottom-left-radius: var(--bs-list-group-border-radius); border-top-right-radius: 0; } + .list-group-horizontal > .list-group-item:last-child:not(:first-child) { border-top-right-radius: var(--bs-list-group-border-radius); border-bottom-left-radius: 0; } + .list-group-horizontal > .list-group-item.active { margin-top: 0; } + .list-group-horizontal > .list-group-item + .list-group-item { border-top-width: var(--bs-list-group-border-width); border-left-width: 0; } + .list-group-horizontal > .list-group-item + .list-group-item.active { margin-left: calc(-1 * var(--bs-list-group-border-width)); border-left-width: var(--bs-list-group-border-width); @@ -5242,128 +5834,160 @@ fieldset:disabled .btn { .list-group-horizontal-sm { flex-direction: row; } + .list-group-horizontal-sm > .list-group-item:first-child:not(:last-child) { border-bottom-left-radius: var(--bs-list-group-border-radius); border-top-right-radius: 0; } + .list-group-horizontal-sm > .list-group-item:last-child:not(:first-child) { border-top-right-radius: var(--bs-list-group-border-radius); border-bottom-left-radius: 0; } + .list-group-horizontal-sm > .list-group-item.active { margin-top: 0; } + .list-group-horizontal-sm > .list-group-item + .list-group-item { border-top-width: var(--bs-list-group-border-width); border-left-width: 0; } + .list-group-horizontal-sm > .list-group-item + .list-group-item.active { margin-left: calc(-1 * var(--bs-list-group-border-width)); border-left-width: var(--bs-list-group-border-width); } } + @media (min-width: 768px) { .list-group-horizontal-md { flex-direction: row; } + .list-group-horizontal-md > .list-group-item:first-child:not(:last-child) { border-bottom-left-radius: var(--bs-list-group-border-radius); border-top-right-radius: 0; } + .list-group-horizontal-md > .list-group-item:last-child:not(:first-child) { border-top-right-radius: var(--bs-list-group-border-radius); border-bottom-left-radius: 0; } + .list-group-horizontal-md > .list-group-item.active { margin-top: 0; } + .list-group-horizontal-md > .list-group-item + .list-group-item { border-top-width: var(--bs-list-group-border-width); border-left-width: 0; } + .list-group-horizontal-md > .list-group-item + .list-group-item.active { margin-left: calc(-1 * var(--bs-list-group-border-width)); border-left-width: var(--bs-list-group-border-width); } } + @media (min-width: 992px) { .list-group-horizontal-lg { flex-direction: row; } + .list-group-horizontal-lg > .list-group-item:first-child:not(:last-child) { border-bottom-left-radius: var(--bs-list-group-border-radius); border-top-right-radius: 0; } + .list-group-horizontal-lg > .list-group-item:last-child:not(:first-child) { border-top-right-radius: var(--bs-list-group-border-radius); border-bottom-left-radius: 0; } + .list-group-horizontal-lg > .list-group-item.active { margin-top: 0; } + .list-group-horizontal-lg > .list-group-item + .list-group-item { border-top-width: var(--bs-list-group-border-width); border-left-width: 0; } + .list-group-horizontal-lg > .list-group-item + .list-group-item.active { margin-left: calc(-1 * var(--bs-list-group-border-width)); border-left-width: var(--bs-list-group-border-width); } } + @media (min-width: 1200px) { .list-group-horizontal-xl { flex-direction: row; } + .list-group-horizontal-xl > .list-group-item:first-child:not(:last-child) { border-bottom-left-radius: var(--bs-list-group-border-radius); border-top-right-radius: 0; } + .list-group-horizontal-xl > .list-group-item:last-child:not(:first-child) { border-top-right-radius: var(--bs-list-group-border-radius); border-bottom-left-radius: 0; } + .list-group-horizontal-xl > .list-group-item.active { margin-top: 0; } + .list-group-horizontal-xl > .list-group-item + .list-group-item { border-top-width: var(--bs-list-group-border-width); border-left-width: 0; } + .list-group-horizontal-xl > .list-group-item + .list-group-item.active { margin-left: calc(-1 * var(--bs-list-group-border-width)); border-left-width: var(--bs-list-group-border-width); } } + @media (min-width: 1400px) { .list-group-horizontal-xxl { flex-direction: row; } + .list-group-horizontal-xxl > .list-group-item:first-child:not(:last-child) { border-bottom-left-radius: var(--bs-list-group-border-radius); border-top-right-radius: 0; } + .list-group-horizontal-xxl > .list-group-item:last-child:not(:first-child) { border-top-right-radius: var(--bs-list-group-border-radius); border-bottom-left-radius: 0; } + .list-group-horizontal-xxl > .list-group-item.active { margin-top: 0; } + .list-group-horizontal-xxl > .list-group-item + .list-group-item { border-top-width: var(--bs-list-group-border-width); border-left-width: 0; } + .list-group-horizontal-xxl > .list-group-item + .list-group-item.active { margin-left: calc(-1 * var(--bs-list-group-border-width)); border-left-width: var(--bs-list-group-border-width); } } + .list-group-flush { border-radius: 0; } + .list-group-flush > .list-group-item { border-width: 0 0 var(--bs-list-group-border-width); } + .list-group-flush > .list-group-item:last-child { border-bottom-width: 0; } @@ -5491,16 +6115,19 @@ fieldset:disabled .btn { border-radius: 0.375rem; opacity: var(--bs-btn-close-opacity); } + .btn-close:hover { color: var(--bs-btn-close-color); text-decoration: none; opacity: var(--bs-btn-close-hover-opacity); } + .btn-close:focus { outline: 0; box-shadow: var(--bs-btn-close-focus-shadow); opacity: var(--bs-btn-close-focus-opacity); } + .btn-close:disabled, .btn-close.disabled { pointer-events: none; @@ -5543,9 +6170,11 @@ fieldset:disabled .btn { box-shadow: var(--bs-toast-box-shadow); border-radius: var(--bs-toast-border-radius); } + .toast.showing { opacity: 0; } + .toast:not(.show) { display: none; } @@ -5558,6 +6187,7 @@ fieldset:disabled .btn { max-width: 100%; pointer-events: none; } + .toast-container > :not(:last-child) { margin-bottom: var(--bs-toast-spacing); } @@ -5578,6 +6208,7 @@ fieldset:disabled .btn { var(--bs-toast-border-radius) - var(--bs-toast-border-width) ); } + .toast-header .btn-close { margin-right: calc(-0.5 * var(--bs-toast-padding-x)); margin-left: var(--bs-toast-padding-x); @@ -5630,18 +6261,22 @@ fieldset:disabled .btn { margin: var(--bs-modal-margin); pointer-events: none; } + .modal.fade .modal-dialog { transition: transform 0.3s ease-out; transform: translate(0, -50px); } + @media (prefers-reduced-motion: reduce) { .modal.fade .modal-dialog { transition: none; } } + .modal.show .modal-dialog { transform: none; } + .modal.modal-static .modal-dialog { transform: scale(1.02); } @@ -5649,10 +6284,12 @@ fieldset:disabled .btn { .modal-dialog-scrollable { height: calc(100% - var(--bs-modal-margin) * 2); } + .modal-dialog-scrollable .modal-content { max-height: 100%; overflow: hidden; } + .modal-dialog-scrollable .modal-body { overflow-y: auto; } @@ -5689,9 +6326,11 @@ fieldset:disabled .btn { height: 100vh; background-color: var(--bs-backdrop-bg); } + .modal-backdrop.fade { opacity: 0; } + .modal-backdrop.show { opacity: var(--bs-backdrop-opacity); } @@ -5707,6 +6346,7 @@ fieldset:disabled .btn { border-top-left-radius: var(--bs-modal-inner-border-radius); border-top-right-radius: var(--bs-modal-inner-border-radius); } + .modal-header .btn-close { padding: calc(var(--bs-modal-header-padding-y) * 0.5) calc(var(--bs-modal-header-padding-x) * 0.5); @@ -5739,6 +6379,7 @@ fieldset:disabled .btn { border-bottom-right-radius: var(--bs-modal-inner-border-radius); border-bottom-left-radius: var(--bs-modal-inner-border-radius); } + .modal-footer > * { margin: calc(var(--bs-modal-footer-gap) * 0.5); } @@ -5748,41 +6389,49 @@ fieldset:disabled .btn { --bs-modal-margin: 1.75rem; --bs-modal-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15); } + .modal-dialog { max-width: var(--bs-modal-width); margin-right: auto; margin-left: auto; } + .modal-sm { --bs-modal-width: 300px; } } + @media (min-width: 992px) { .modal-lg, .modal-xl { --bs-modal-width: 800px; } } + @media (min-width: 1200px) { .modal-xl { --bs-modal-width: 1140px; } } + .modal-fullscreen { width: 100vw; max-width: none; height: 100%; margin: 0; } + .modal-fullscreen .modal-content { height: 100%; border: 0; border-radius: 0; } + .modal-fullscreen .modal-header, .modal-fullscreen .modal-footer { border-radius: 0; } + .modal-fullscreen .modal-body { overflow-y: auto; } @@ -5794,19 +6443,23 @@ fieldset:disabled .btn { height: 100%; margin: 0; } + .modal-fullscreen-sm-down .modal-content { height: 100%; border: 0; border-radius: 0; } + .modal-fullscreen-sm-down .modal-header, .modal-fullscreen-sm-down .modal-footer { border-radius: 0; } + .modal-fullscreen-sm-down .modal-body { overflow-y: auto; } } + @media (max-width: 767.98px) { .modal-fullscreen-md-down { width: 100vw; @@ -5814,19 +6467,23 @@ fieldset:disabled .btn { height: 100%; margin: 0; } + .modal-fullscreen-md-down .modal-content { height: 100%; border: 0; border-radius: 0; } + .modal-fullscreen-md-down .modal-header, .modal-fullscreen-md-down .modal-footer { border-radius: 0; } + .modal-fullscreen-md-down .modal-body { overflow-y: auto; } } + @media (max-width: 991.98px) { .modal-fullscreen-lg-down { width: 100vw; @@ -5834,19 +6491,23 @@ fieldset:disabled .btn { height: 100%; margin: 0; } + .modal-fullscreen-lg-down .modal-content { height: 100%; border: 0; border-radius: 0; } + .modal-fullscreen-lg-down .modal-header, .modal-fullscreen-lg-down .modal-footer { border-radius: 0; } + .modal-fullscreen-lg-down .modal-body { overflow-y: auto; } } + @media (max-width: 1199.98px) { .modal-fullscreen-xl-down { width: 100vw; @@ -5854,19 +6515,23 @@ fieldset:disabled .btn { height: 100%; margin: 0; } + .modal-fullscreen-xl-down .modal-content { height: 100%; border: 0; border-radius: 0; } + .modal-fullscreen-xl-down .modal-header, .modal-fullscreen-xl-down .modal-footer { border-radius: 0; } + .modal-fullscreen-xl-down .modal-body { overflow-y: auto; } } + @media (max-width: 1399.98px) { .modal-fullscreen-xxl-down { width: 100vw; @@ -5874,19 +6539,23 @@ fieldset:disabled .btn { height: 100%; margin: 0; } + .modal-fullscreen-xxl-down .modal-content { height: 100%; border: 0; border-radius: 0; } + .modal-fullscreen-xxl-down .modal-header, .modal-fullscreen-xxl-down .modal-footer { border-radius: 0; } + .modal-fullscreen-xxl-down .modal-body { overflow-y: auto; } } + .tooltip { --bs-tooltip-zindex: 1080; --bs-tooltip-max-width: 200px; @@ -5921,14 +6590,17 @@ fieldset:disabled .btn { word-wrap: break-word; opacity: 0; } + .tooltip.show { opacity: var(--bs-tooltip-opacity); } + .tooltip .tooltip-arrow { display: block; width: var(--bs-tooltip-arrow-width); height: var(--bs-tooltip-arrow-height); } + .tooltip .tooltip-arrow::before { position: absolute; content: ''; @@ -5940,6 +6612,7 @@ fieldset:disabled .btn { .bs-tooltip-auto[data-popper-placement^='top'] .tooltip-arrow { bottom: calc(-1 * var(--bs-tooltip-arrow-height)); } + .bs-tooltip-top .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^='top'] .tooltip-arrow::before { top: -1px; @@ -5955,6 +6628,7 @@ fieldset:disabled .btn { width: var(--bs-tooltip-arrow-height); height: var(--bs-tooltip-arrow-width); } + .bs-tooltip-end .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^='right'] .tooltip-arrow::before { right: -1px; @@ -5968,6 +6642,7 @@ fieldset:disabled .btn { .bs-tooltip-auto[data-popper-placement^='bottom'] .tooltip-arrow { top: calc(-1 * var(--bs-tooltip-arrow-height)); } + .bs-tooltip-bottom .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^='bottom'] .tooltip-arrow::before { bottom: -1px; @@ -5983,6 +6658,7 @@ fieldset:disabled .btn { width: var(--bs-tooltip-arrow-height); height: var(--bs-tooltip-arrow-width); } + .bs-tooltip-start .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^='left'] .tooltip-arrow::before { left: -1px; @@ -6048,11 +6724,13 @@ fieldset:disabled .btn { border: var(--bs-popover-border-width) solid var(--bs-popover-border-color); border-radius: var(--bs-popover-border-radius); } + .popover .popover-arrow { display: block; width: var(--bs-popover-arrow-width); height: var(--bs-popover-arrow-height); } + .popover .popover-arrow::before, .popover .popover-arrow::after { position: absolute; @@ -6069,6 +6747,7 @@ fieldset:disabled .btn { -1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width) ); } + .bs-popover-top > .popover-arrow::before, .bs-popover-auto[data-popper-placement^='top'] > .popover-arrow::before, .bs-popover-top > .popover-arrow::after, @@ -6076,11 +6755,13 @@ fieldset:disabled .btn { border-width: var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * 0.5) 0; } + .bs-popover-top > .popover-arrow::before, .bs-popover-auto[data-popper-placement^='top'] > .popover-arrow::before { bottom: 0; border-top-color: var(--bs-popover-arrow-border); } + .bs-popover-top > .popover-arrow::after, .bs-popover-auto[data-popper-placement^='top'] > .popover-arrow::after { bottom: var(--bs-popover-border-width); @@ -6096,6 +6777,7 @@ fieldset:disabled .btn { width: var(--bs-popover-arrow-height); height: var(--bs-popover-arrow-width); } + .bs-popover-end > .popover-arrow::before, .bs-popover-auto[data-popper-placement^='right'] > .popover-arrow::before, .bs-popover-end > .popover-arrow::after, @@ -6103,11 +6785,13 @@ fieldset:disabled .btn { border-width: calc(var(--bs-popover-arrow-width) * 0.5) var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * 0.5) 0; } + .bs-popover-end > .popover-arrow::before, .bs-popover-auto[data-popper-placement^='right'] > .popover-arrow::before { left: 0; border-right-color: var(--bs-popover-arrow-border); } + .bs-popover-end > .popover-arrow::after, .bs-popover-auto[data-popper-placement^='right'] > .popover-arrow::after { left: var(--bs-popover-border-width); @@ -6121,6 +6805,7 @@ fieldset:disabled .btn { -1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width) ); } + .bs-popover-bottom > .popover-arrow::before, .bs-popover-auto[data-popper-placement^='bottom'] > .popover-arrow::before, .bs-popover-bottom > .popover-arrow::after, @@ -6128,16 +6813,19 @@ fieldset:disabled .btn { border-width: 0 calc(var(--bs-popover-arrow-width) * 0.5) var(--bs-popover-arrow-height); } + .bs-popover-bottom > .popover-arrow::before, .bs-popover-auto[data-popper-placement^='bottom'] > .popover-arrow::before { top: 0; border-bottom-color: var(--bs-popover-arrow-border); } + .bs-popover-bottom > .popover-arrow::after, .bs-popover-auto[data-popper-placement^='bottom'] > .popover-arrow::after { top: var(--bs-popover-border-width); border-bottom-color: var(--bs-popover-bg); } + .bs-popover-bottom .popover-header::before, .bs-popover-auto[data-popper-placement^='bottom'] .popover-header::before { position: absolute; @@ -6160,6 +6848,7 @@ fieldset:disabled .btn { width: var(--bs-popover-arrow-height); height: var(--bs-popover-arrow-width); } + .bs-popover-start > .popover-arrow::before, .bs-popover-auto[data-popper-placement^='left'] > .popover-arrow::before, .bs-popover-start > .popover-arrow::after, @@ -6167,11 +6856,13 @@ fieldset:disabled .btn { border-width: calc(var(--bs-popover-arrow-width) * 0.5) 0 calc(var(--bs-popover-arrow-width) * 0.5) var(--bs-popover-arrow-height); } + .bs-popover-start > .popover-arrow::before, .bs-popover-auto[data-popper-placement^='left'] > .popover-arrow::before { right: 0; border-left-color: var(--bs-popover-arrow-border); } + .bs-popover-start > .popover-arrow::after, .bs-popover-auto[data-popper-placement^='left'] > .popover-arrow::after { right: var(--bs-popover-border-width); @@ -6190,6 +6881,7 @@ fieldset:disabled .btn { border-top-left-radius: var(--bs-popover-inner-border-radius); border-top-right-radius: var(--bs-popover-inner-border-radius); } + .popover-header:empty { display: none; } @@ -6212,6 +6904,7 @@ fieldset:disabled .btn { width: 100%; overflow: hidden; } + .carousel-inner::after { display: block; clear: both; @@ -6227,6 +6920,7 @@ fieldset:disabled .btn { backface-visibility: hidden; transition: transform 0.6s ease-in-out; } + @media (prefers-reduced-motion: reduce) { .carousel-item { transition: none; @@ -6254,18 +6948,21 @@ fieldset:disabled .btn { transition-property: opacity; transform: none; } + .carousel-fade .carousel-item.active, .carousel-fade .carousel-item-next.carousel-item-start, .carousel-fade .carousel-item-prev.carousel-item-end { z-index: 1; opacity: 1; } + .carousel-fade .active.carousel-item-start, .carousel-fade .active.carousel-item-end { z-index: 0; opacity: 0; transition: opacity 0s 0.6s; } + @media (prefers-reduced-motion: reduce) { .carousel-fade .active.carousel-item-start, .carousel-fade .active.carousel-item-end { @@ -6291,12 +6988,14 @@ fieldset:disabled .btn { opacity: 0.5; transition: opacity 0.15s ease; } + @media (prefers-reduced-motion: reduce) { .carousel-control-prev, .carousel-control-next { transition: none; } } + .carousel-control-prev:hover, .carousel-control-prev:focus, .carousel-control-next:hover, @@ -6354,6 +7053,7 @@ fieldset:disabled .btn { margin-bottom: 1rem; margin-left: 15%; } + .carousel-indicators [data-bs-target] { box-sizing: content-box; flex: 0 1 auto; @@ -6372,11 +7072,13 @@ fieldset:disabled .btn { opacity: 0.5; transition: opacity 0.6s ease; } + @media (prefers-reduced-motion: reduce) { .carousel-indicators [data-bs-target] { transition: none; } } + .carousel-indicators .active { opacity: 1; } @@ -6396,9 +7098,11 @@ fieldset:disabled .btn { .carousel-dark .carousel-control-next-icon { filter: invert(1) grayscale(100); } + .carousel-dark .carousel-indicators [data-bs-target] { background-color: #000; } + .carousel-dark .carousel-caption { color: #000; } @@ -6409,10 +7113,12 @@ fieldset:disabled .btn { [data-bs-theme='dark'].carousel .carousel-control-next-icon { filter: invert(1) grayscale(100); } + [data-bs-theme='dark'] .carousel .carousel-indicators [data-bs-target], [data-bs-theme='dark'].carousel .carousel-indicators [data-bs-target] { background-color: #000; } + [data-bs-theme='dark'] .carousel .carousel-caption, [data-bs-theme='dark'].carousel .carousel-caption { color: #000; @@ -6434,6 +7140,7 @@ fieldset:disabled .btn { transform: rotate(360deg) /* rtl:ignore */; } } + .spinner-border { --bs-spinner-width: 2rem; --bs-spinner-height: 2rem; @@ -6455,11 +7162,13 @@ fieldset:disabled .btn { 0% { transform: scale(0); } + 50% { opacity: 1; transform: none; } } + .spinner-grow { --bs-spinner-width: 2rem; --bs-spinner-height: 2rem; @@ -6481,6 +7190,7 @@ fieldset:disabled .btn { --bs-spinner-animation-speed: 1.5s; } } + .offcanvas, .offcanvas-xxl, .offcanvas-xl, @@ -6517,11 +7227,13 @@ fieldset:disabled .btn { transition: var(--bs-offcanvas-transition); } } + @media (max-width: 575.98px) and (prefers-reduced-motion: reduce) { .offcanvas-sm { transition: none; } } + @media (max-width: 575.98px) { .offcanvas-sm.offcanvas-start { top: 0; @@ -6531,6 +7243,7 @@ fieldset:disabled .btn { var(--bs-offcanvas-border-color); transform: translateX(-100%); } + .offcanvas-sm.offcanvas-end { top: 0; right: 0; @@ -6539,6 +7252,7 @@ fieldset:disabled .btn { var(--bs-offcanvas-border-color); transform: translateX(100%); } + .offcanvas-sm.offcanvas-top { top: 0; right: 0; @@ -6549,6 +7263,7 @@ fieldset:disabled .btn { var(--bs-offcanvas-border-color); transform: translateY(-100%); } + .offcanvas-sm.offcanvas-bottom { right: 0; left: 0; @@ -6558,25 +7273,30 @@ fieldset:disabled .btn { var(--bs-offcanvas-border-color); transform: translateY(100%); } + .offcanvas-sm.showing, .offcanvas-sm.show:not(.hiding) { transform: none; } + .offcanvas-sm.showing, .offcanvas-sm.hiding, .offcanvas-sm.show { visibility: visible; } } + @media (min-width: 576px) { .offcanvas-sm { --bs-offcanvas-height: auto; --bs-offcanvas-border-width: 0; background-color: transparent !important; } + .offcanvas-sm .offcanvas-header { display: none; } + .offcanvas-sm .offcanvas-body { display: flex; flex-grow: 0; @@ -6602,11 +7322,13 @@ fieldset:disabled .btn { transition: var(--bs-offcanvas-transition); } } + @media (max-width: 767.98px) and (prefers-reduced-motion: reduce) { .offcanvas-md { transition: none; } } + @media (max-width: 767.98px) { .offcanvas-md.offcanvas-start { top: 0; @@ -6616,6 +7338,7 @@ fieldset:disabled .btn { var(--bs-offcanvas-border-color); transform: translateX(-100%); } + .offcanvas-md.offcanvas-end { top: 0; right: 0; @@ -6624,6 +7347,7 @@ fieldset:disabled .btn { var(--bs-offcanvas-border-color); transform: translateX(100%); } + .offcanvas-md.offcanvas-top { top: 0; right: 0; @@ -6634,6 +7358,7 @@ fieldset:disabled .btn { var(--bs-offcanvas-border-color); transform: translateY(-100%); } + .offcanvas-md.offcanvas-bottom { right: 0; left: 0; @@ -6643,25 +7368,30 @@ fieldset:disabled .btn { var(--bs-offcanvas-border-color); transform: translateY(100%); } + .offcanvas-md.showing, .offcanvas-md.show:not(.hiding) { transform: none; } + .offcanvas-md.showing, .offcanvas-md.hiding, .offcanvas-md.show { visibility: visible; } } + @media (min-width: 768px) { .offcanvas-md { --bs-offcanvas-height: auto; --bs-offcanvas-border-width: 0; background-color: transparent !important; } + .offcanvas-md .offcanvas-header { display: none; } + .offcanvas-md .offcanvas-body { display: flex; flex-grow: 0; @@ -6687,11 +7417,13 @@ fieldset:disabled .btn { transition: var(--bs-offcanvas-transition); } } + @media (max-width: 991.98px) and (prefers-reduced-motion: reduce) { .offcanvas-lg { transition: none; } } + @media (max-width: 991.98px) { .offcanvas-lg.offcanvas-start { top: 0; @@ -6701,6 +7433,7 @@ fieldset:disabled .btn { var(--bs-offcanvas-border-color); transform: translateX(-100%); } + .offcanvas-lg.offcanvas-end { top: 0; right: 0; @@ -6709,6 +7442,7 @@ fieldset:disabled .btn { var(--bs-offcanvas-border-color); transform: translateX(100%); } + .offcanvas-lg.offcanvas-top { top: 0; right: 0; @@ -6719,6 +7453,7 @@ fieldset:disabled .btn { var(--bs-offcanvas-border-color); transform: translateY(-100%); } + .offcanvas-lg.offcanvas-bottom { right: 0; left: 0; @@ -6728,25 +7463,30 @@ fieldset:disabled .btn { var(--bs-offcanvas-border-color); transform: translateY(100%); } + .offcanvas-lg.showing, .offcanvas-lg.show:not(.hiding) { transform: none; } + .offcanvas-lg.showing, .offcanvas-lg.hiding, .offcanvas-lg.show { visibility: visible; } } + @media (min-width: 992px) { .offcanvas-lg { --bs-offcanvas-height: auto; --bs-offcanvas-border-width: 0; background-color: transparent !important; } + .offcanvas-lg .offcanvas-header { display: none; } + .offcanvas-lg .offcanvas-body { display: flex; flex-grow: 0; @@ -6772,11 +7512,13 @@ fieldset:disabled .btn { transition: var(--bs-offcanvas-transition); } } + @media (max-width: 1199.98px) and (prefers-reduced-motion: reduce) { .offcanvas-xl { transition: none; } } + @media (max-width: 1199.98px) { .offcanvas-xl.offcanvas-start { top: 0; @@ -6786,6 +7528,7 @@ fieldset:disabled .btn { var(--bs-offcanvas-border-color); transform: translateX(-100%); } + .offcanvas-xl.offcanvas-end { top: 0; right: 0; @@ -6794,6 +7537,7 @@ fieldset:disabled .btn { var(--bs-offcanvas-border-color); transform: translateX(100%); } + .offcanvas-xl.offcanvas-top { top: 0; right: 0; @@ -6804,6 +7548,7 @@ fieldset:disabled .btn { var(--bs-offcanvas-border-color); transform: translateY(-100%); } + .offcanvas-xl.offcanvas-bottom { right: 0; left: 0; @@ -6813,25 +7558,30 @@ fieldset:disabled .btn { var(--bs-offcanvas-border-color); transform: translateY(100%); } + .offcanvas-xl.showing, .offcanvas-xl.show:not(.hiding) { transform: none; } + .offcanvas-xl.showing, .offcanvas-xl.hiding, .offcanvas-xl.show { visibility: visible; } } + @media (min-width: 1200px) { .offcanvas-xl { --bs-offcanvas-height: auto; --bs-offcanvas-border-width: 0; background-color: transparent !important; } + .offcanvas-xl .offcanvas-header { display: none; } + .offcanvas-xl .offcanvas-body { display: flex; flex-grow: 0; @@ -6857,11 +7607,13 @@ fieldset:disabled .btn { transition: var(--bs-offcanvas-transition); } } + @media (max-width: 1399.98px) and (prefers-reduced-motion: reduce) { .offcanvas-xxl { transition: none; } } + @media (max-width: 1399.98px) { .offcanvas-xxl.offcanvas-start { top: 0; @@ -6871,6 +7623,7 @@ fieldset:disabled .btn { var(--bs-offcanvas-border-color); transform: translateX(-100%); } + .offcanvas-xxl.offcanvas-end { top: 0; right: 0; @@ -6879,6 +7632,7 @@ fieldset:disabled .btn { var(--bs-offcanvas-border-color); transform: translateX(100%); } + .offcanvas-xxl.offcanvas-top { top: 0; right: 0; @@ -6889,6 +7643,7 @@ fieldset:disabled .btn { var(--bs-offcanvas-border-color); transform: translateY(-100%); } + .offcanvas-xxl.offcanvas-bottom { right: 0; left: 0; @@ -6898,25 +7653,30 @@ fieldset:disabled .btn { var(--bs-offcanvas-border-color); transform: translateY(100%); } + .offcanvas-xxl.showing, .offcanvas-xxl.show:not(.hiding) { transform: none; } + .offcanvas-xxl.showing, .offcanvas-xxl.hiding, .offcanvas-xxl.show { visibility: visible; } } + @media (min-width: 1400px) { .offcanvas-xxl { --bs-offcanvas-height: auto; --bs-offcanvas-border-width: 0; background-color: transparent !important; } + .offcanvas-xxl .offcanvas-header { display: none; } + .offcanvas-xxl .offcanvas-body { display: flex; flex-grow: 0; @@ -6940,11 +7700,13 @@ fieldset:disabled .btn { outline: 0; transition: var(--bs-offcanvas-transition); } + @media (prefers-reduced-motion: reduce) { .offcanvas { transition: none; } } + .offcanvas.offcanvas-start { top: 0; left: 0; @@ -6953,6 +7715,7 @@ fieldset:disabled .btn { var(--bs-offcanvas-border-color); transform: translateX(-100%); } + .offcanvas.offcanvas-end { top: 0; right: 0; @@ -6961,6 +7724,7 @@ fieldset:disabled .btn { var(--bs-offcanvas-border-color); transform: translateX(100%); } + .offcanvas.offcanvas-top { top: 0; right: 0; @@ -6971,6 +7735,7 @@ fieldset:disabled .btn { var(--bs-offcanvas-border-color); transform: translateY(-100%); } + .offcanvas.offcanvas-bottom { right: 0; left: 0; @@ -6980,10 +7745,12 @@ fieldset:disabled .btn { var(--bs-offcanvas-border-color); transform: translateY(100%); } + .offcanvas.showing, .offcanvas.show:not(.hiding) { transform: none; } + .offcanvas.showing, .offcanvas.hiding, .offcanvas.show { @@ -6999,9 +7766,11 @@ fieldset:disabled .btn { height: 100vh; background-color: #000; } + .offcanvas-backdrop.fade { opacity: 0; } + .offcanvas-backdrop.show { opacity: 0.5; } @@ -7012,6 +7781,7 @@ fieldset:disabled .btn { justify-content: space-between; padding: var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x); } + .offcanvas-header .btn-close { padding: calc(var(--bs-offcanvas-padding-y) * 0.5) calc(var(--bs-offcanvas-padding-x) * 0.5); @@ -7039,6 +7809,7 @@ fieldset:disabled .btn { background-color: currentcolor; opacity: 0.5; } + .placeholder.btn::before { display: inline-block; content: ''; @@ -7065,6 +7836,7 @@ fieldset:disabled .btn { opacity: 0.2; } } + .placeholder-wave { mask-image: linear-gradient( 130deg, @@ -7081,6 +7853,7 @@ fieldset:disabled .btn { mask-position: -200% 0%; } } + .clearfix::after { display: block; clear: both; @@ -7134,6 +7907,7 @@ fieldset:disabled .btn { var(--bs-link-underline-opacity, 1) ) !important; } + .link-primary:hover, .link-primary:focus { color: RGBA(90, 201, 137, var(--bs-link-opacity, 1)) !important; @@ -7152,6 +7926,7 @@ fieldset:disabled .btn { var(--bs-link-underline-opacity, 1) ) !important; } + .link-secondary:hover, .link-secondary:focus { color: RGBA(90, 90, 90, var(--bs-link-opacity, 1)) !important; @@ -7170,6 +7945,7 @@ fieldset:disabled .btn { var(--bs-link-underline-opacity, 1) ) !important; } + .link-success:hover, .link-success:focus { color: RGBA(90, 201, 137, var(--bs-link-opacity, 1)) !important; @@ -7188,6 +7964,7 @@ fieldset:disabled .btn { var(--bs-link-underline-opacity, 1) ) !important; } + .link-info:hover, .link-info:focus { color: RGBA(61, 213, 243, var(--bs-link-opacity, 1)) !important; @@ -7206,6 +7983,7 @@ fieldset:disabled .btn { var(--bs-link-underline-opacity, 1) ) !important; } + .link-warning:hover, .link-warning:focus { color: RGBA(254, 201, 122, var(--bs-link-opacity, 1)) !important; @@ -7224,6 +8002,7 @@ fieldset:disabled .btn { var(--bs-link-underline-opacity, 1) ) !important; } + .link-danger:hover, .link-danger:focus { color: RGBA(176, 42, 55, var(--bs-link-opacity, 1)) !important; @@ -7242,6 +8021,7 @@ fieldset:disabled .btn { var(--bs-link-underline-opacity, 1) ) !important; } + .link-light:hover, .link-light:focus { color: RGBA(249, 250, 251, var(--bs-link-opacity, 1)) !important; @@ -7260,6 +8040,7 @@ fieldset:disabled .btn { var(--bs-link-underline-opacity, 1) ) !important; } + .link-dark:hover, .link-dark:focus { color: RGBA(26, 30, 33, var(--bs-link-opacity, 1)) !important; @@ -7281,6 +8062,7 @@ fieldset:disabled .btn { var(--bs-link-underline-opacity, 1) ) !important; } + .link-body-emphasis:hover, .link-body-emphasis:focus { color: RGBA( @@ -7311,6 +8093,7 @@ fieldset:disabled .btn { text-underline-offset: 0.25em; backface-visibility: hidden; } + .icon-link > .bi { flex-shrink: 0; width: 1em; @@ -7318,6 +8101,7 @@ fieldset:disabled .btn { fill: currentcolor; transition: 0.2s ease-in-out transform; } + @media (prefers-reduced-motion: reduce) { .icon-link > .bi { transition: none; @@ -7333,11 +8117,13 @@ fieldset:disabled .btn { position: relative; width: 100%; } + .ratio::before { display: block; padding-top: var(--bs-aspect-ratio); content: ''; } + .ratio > * { position: absolute; top: 0; @@ -7396,60 +8182,70 @@ fieldset:disabled .btn { top: 0; z-index: 1020; } + .sticky-sm-bottom { position: sticky; bottom: 0; z-index: 1020; } } + @media (min-width: 768px) { .sticky-md-top { position: sticky; top: 0; z-index: 1020; } + .sticky-md-bottom { position: sticky; bottom: 0; z-index: 1020; } } + @media (min-width: 992px) { .sticky-lg-top { position: sticky; top: 0; z-index: 1020; } + .sticky-lg-bottom { position: sticky; bottom: 0; z-index: 1020; } } + @media (min-width: 1200px) { .sticky-xl-top { position: sticky; top: 0; z-index: 1020; } + .sticky-xl-bottom { position: sticky; bottom: 0; z-index: 1020; } } + @media (min-width: 1400px) { .sticky-xxl-top { position: sticky; top: 0; z-index: 1020; } + .sticky-xxl-bottom { position: sticky; bottom: 0; z-index: 1020; } } + .hstack { display: flex; flex-direction: row; @@ -7475,6 +8271,7 @@ fieldset:disabled .btn { white-space: nowrap !important; border: 0 !important; } + .visually-hidden:not(caption), .visually-hidden-focusable:not(:focus):not(:focus-within):not(caption) { position: absolute !important; @@ -9563,2801 +10360,3686 @@ fieldset:disabled .btn { .float-sm-start { float: left !important; } + .float-sm-end { float: right !important; } + .float-sm-none { float: none !important; } + .object-fit-sm-contain { object-fit: contain !important; } + .object-fit-sm-cover { object-fit: cover !important; } + .object-fit-sm-fill { object-fit: fill !important; } + .object-fit-sm-scale { object-fit: scale-down !important; } + .object-fit-sm-none { object-fit: none !important; } + .d-sm-inline { display: inline !important; } + .d-sm-inline-block { display: inline-block !important; } + .d-sm-block { display: block !important; } + .d-sm-grid { display: grid !important; } + .d-sm-inline-grid { display: inline-grid !important; } + .d-sm-table { display: table !important; } + .d-sm-table-row { display: table-row !important; } + .d-sm-table-cell { display: table-cell !important; } + .d-sm-flex { display: flex !important; } + .d-sm-inline-flex { display: inline-flex !important; } + .d-sm-none { display: none !important; } + .flex-sm-fill { flex: 1 1 auto !important; } + .flex-sm-row { flex-direction: row !important; } + .flex-sm-column { flex-direction: column !important; } + .flex-sm-row-reverse { flex-direction: row-reverse !important; } + .flex-sm-column-reverse { flex-direction: column-reverse !important; } + .flex-sm-grow-0 { flex-grow: 0 !important; } + .flex-sm-grow-1 { flex-grow: 1 !important; } + .flex-sm-shrink-0 { flex-shrink: 0 !important; } + .flex-sm-shrink-1 { flex-shrink: 1 !important; } + .flex-sm-wrap { flex-wrap: wrap !important; } + .flex-sm-nowrap { flex-wrap: nowrap !important; } + .flex-sm-wrap-reverse { flex-wrap: wrap-reverse !important; } + .justify-content-sm-start { justify-content: flex-start !important; } + .justify-content-sm-end { justify-content: flex-end !important; } + .justify-content-sm-center { justify-content: center !important; } + .justify-content-sm-between { justify-content: space-between !important; } + .justify-content-sm-around { justify-content: space-around !important; } + .justify-content-sm-evenly { justify-content: space-evenly !important; } + .align-items-sm-start { align-items: flex-start !important; } + .align-items-sm-end { align-items: flex-end !important; } + .align-items-sm-center { align-items: center !important; } + .align-items-sm-baseline { align-items: baseline !important; } + .align-items-sm-stretch { align-items: stretch !important; } + .align-content-sm-start { align-content: flex-start !important; } + .align-content-sm-end { align-content: flex-end !important; } + .align-content-sm-center { align-content: center !important; } + .align-content-sm-between { align-content: space-between !important; } + .align-content-sm-around { align-content: space-around !important; } + .align-content-sm-stretch { align-content: stretch !important; } + .align-self-sm-auto { align-self: auto !important; } + .align-self-sm-start { align-self: flex-start !important; } + .align-self-sm-end { align-self: flex-end !important; } + .align-self-sm-center { align-self: center !important; } + .align-self-sm-baseline { align-self: baseline !important; } + .align-self-sm-stretch { align-self: stretch !important; } + .order-sm-first { order: -1 !important; } + .order-sm-0 { order: 0 !important; } + .order-sm-1 { order: 1 !important; } + .order-sm-2 { order: 2 !important; } + .order-sm-3 { order: 3 !important; } + .order-sm-4 { order: 4 !important; } + .order-sm-5 { order: 5 !important; } + .order-sm-last { order: 6 !important; } + .m-sm-0 { margin: 0 !important; } + .m-sm-1 { margin: 0.25rem !important; } + .m-sm-2 { margin: 0.5rem !important; } + .m-sm-3 { margin: 1rem !important; } + .m-sm-4 { margin: 1.5rem !important; } + .m-sm-5 { margin: 3rem !important; } + .m-sm-auto { margin: auto !important; } + .mx-sm-0 { margin-right: 0 !important; margin-left: 0 !important; } + .mx-sm-1 { margin-right: 0.25rem !important; margin-left: 0.25rem !important; } + .mx-sm-2 { margin-right: 0.5rem !important; margin-left: 0.5rem !important; } + .mx-sm-3 { margin-right: 1rem !important; margin-left: 1rem !important; } + .mx-sm-4 { margin-right: 1.5rem !important; margin-left: 1.5rem !important; } + .mx-sm-5 { margin-right: 3rem !important; margin-left: 3rem !important; } + .mx-sm-auto { margin-right: auto !important; margin-left: auto !important; } + .my-sm-0 { margin-top: 0 !important; margin-bottom: 0 !important; } + .my-sm-1 { margin-top: 0.25rem !important; margin-bottom: 0.25rem !important; } + .my-sm-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } + .my-sm-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } + .my-sm-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } + .my-sm-5 { margin-top: 3rem !important; margin-bottom: 3rem !important; } + .my-sm-auto { margin-top: auto !important; margin-bottom: auto !important; } + .mt-sm-0 { margin-top: 0 !important; } + .mt-sm-1 { margin-top: 0.25rem !important; } + .mt-sm-2 { margin-top: 0.5rem !important; } + .mt-sm-3 { margin-top: 1rem !important; } + .mt-sm-4 { margin-top: 1.5rem !important; } + .mt-sm-5 { margin-top: 3rem !important; } + .mt-sm-auto { margin-top: auto !important; } + .me-sm-0 { margin-right: 0 !important; } + .me-sm-1 { margin-right: 0.25rem !important; } + .me-sm-2 { margin-right: 0.5rem !important; } + .me-sm-3 { margin-right: 1rem !important; } + .me-sm-4 { margin-right: 1.5rem !important; } + .me-sm-5 { margin-right: 3rem !important; } + .me-sm-auto { margin-right: auto !important; } + .mb-sm-0 { margin-bottom: 0 !important; } + .mb-sm-1 { margin-bottom: 0.25rem !important; } + .mb-sm-2 { margin-bottom: 0.5rem !important; } + .mb-sm-3 { margin-bottom: 1rem !important; } + .mb-sm-4 { margin-bottom: 1.5rem !important; } + .mb-sm-5 { margin-bottom: 3rem !important; } + .mb-sm-auto { margin-bottom: auto !important; } + .ms-sm-0 { margin-left: 0 !important; } + .ms-sm-1 { margin-left: 0.25rem !important; } + .ms-sm-2 { margin-left: 0.5rem !important; } + .ms-sm-3 { margin-left: 1rem !important; } + .ms-sm-4 { margin-left: 1.5rem !important; } + .ms-sm-5 { margin-left: 3rem !important; } + .ms-sm-auto { margin-left: auto !important; } + .p-sm-0 { padding: 0 !important; } + .p-sm-1 { padding: 0.25rem !important; } + .p-sm-2 { padding: 0.5rem !important; } + .p-sm-3 { padding: 1rem !important; } + .p-sm-4 { padding: 1.5rem !important; } + .p-sm-5 { padding: 3rem !important; } + .px-sm-0 { padding-right: 0 !important; padding-left: 0 !important; } + .px-sm-1 { padding-right: 0.25rem !important; padding-left: 0.25rem !important; } + .px-sm-2 { padding-right: 0.5rem !important; padding-left: 0.5rem !important; } + .px-sm-3 { padding-right: 1rem !important; padding-left: 1rem !important; } + .px-sm-4 { padding-right: 1.5rem !important; padding-left: 1.5rem !important; } + .px-sm-5 { padding-right: 3rem !important; padding-left: 3rem !important; } + .py-sm-0 { padding-top: 0 !important; padding-bottom: 0 !important; } + .py-sm-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } + .py-sm-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } + .py-sm-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } + .py-sm-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } + .py-sm-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } + .pt-sm-0 { padding-top: 0 !important; } + .pt-sm-1 { padding-top: 0.25rem !important; } + .pt-sm-2 { padding-top: 0.5rem !important; } + .pt-sm-3 { padding-top: 1rem !important; } + .pt-sm-4 { padding-top: 1.5rem !important; } + .pt-sm-5 { padding-top: 3rem !important; } + .pe-sm-0 { padding-right: 0 !important; } + .pe-sm-1 { padding-right: 0.25rem !important; } + .pe-sm-2 { padding-right: 0.5rem !important; } + .pe-sm-3 { padding-right: 1rem !important; } + .pe-sm-4 { padding-right: 1.5rem !important; } + .pe-sm-5 { padding-right: 3rem !important; } + .pb-sm-0 { padding-bottom: 0 !important; } + .pb-sm-1 { padding-bottom: 0.25rem !important; } + .pb-sm-2 { padding-bottom: 0.5rem !important; } + .pb-sm-3 { padding-bottom: 1rem !important; } + .pb-sm-4 { padding-bottom: 1.5rem !important; } + .pb-sm-5 { padding-bottom: 3rem !important; } + .ps-sm-0 { padding-left: 0 !important; } + .ps-sm-1 { padding-left: 0.25rem !important; } + .ps-sm-2 { padding-left: 0.5rem !important; } + .ps-sm-3 { padding-left: 1rem !important; } + .ps-sm-4 { padding-left: 1.5rem !important; } + .ps-sm-5 { padding-left: 3rem !important; } + .gap-sm-0 { gap: 0 !important; } + .gap-sm-1 { gap: 0.25rem !important; } + .gap-sm-2 { gap: 0.5rem !important; } + .gap-sm-3 { gap: 1rem !important; } + .gap-sm-4 { gap: 1.5rem !important; } + .gap-sm-5 { gap: 3rem !important; } + .row-gap-sm-0 { row-gap: 0 !important; } + .row-gap-sm-1 { row-gap: 0.25rem !important; } + .row-gap-sm-2 { row-gap: 0.5rem !important; } + .row-gap-sm-3 { row-gap: 1rem !important; } + .row-gap-sm-4 { row-gap: 1.5rem !important; } + .row-gap-sm-5 { row-gap: 3rem !important; } + .column-gap-sm-0 { column-gap: 0 !important; } + .column-gap-sm-1 { column-gap: 0.25rem !important; } + .column-gap-sm-2 { column-gap: 0.5rem !important; } + .column-gap-sm-3 { column-gap: 1rem !important; } + .column-gap-sm-4 { column-gap: 1.5rem !important; } + .column-gap-sm-5 { column-gap: 3rem !important; } + .text-sm-start { text-align: left !important; } + .text-sm-end { text-align: right !important; } + .text-sm-center { text-align: center !important; } } + @media (min-width: 768px) { .float-md-start { float: left !important; } + .float-md-end { float: right !important; } + .float-md-none { float: none !important; } + .object-fit-md-contain { object-fit: contain !important; } + .object-fit-md-cover { object-fit: cover !important; } + .object-fit-md-fill { object-fit: fill !important; } + .object-fit-md-scale { object-fit: scale-down !important; } + .object-fit-md-none { object-fit: none !important; } + .d-md-inline { display: inline !important; } + .d-md-inline-block { display: inline-block !important; } + .d-md-block { display: block !important; } + .d-md-grid { display: grid !important; } + .d-md-inline-grid { display: inline-grid !important; } + .d-md-table { display: table !important; } + .d-md-table-row { display: table-row !important; } + .d-md-table-cell { display: table-cell !important; } + .d-md-flex { display: flex !important; } + .d-md-inline-flex { display: inline-flex !important; } + .d-md-none { display: none !important; } + .flex-md-fill { flex: 1 1 auto !important; } + .flex-md-row { flex-direction: row !important; } + .flex-md-column { flex-direction: column !important; } + .flex-md-row-reverse { flex-direction: row-reverse !important; } + .flex-md-column-reverse { flex-direction: column-reverse !important; } + .flex-md-grow-0 { flex-grow: 0 !important; } + .flex-md-grow-1 { flex-grow: 1 !important; } + .flex-md-shrink-0 { flex-shrink: 0 !important; } + .flex-md-shrink-1 { flex-shrink: 1 !important; } + .flex-md-wrap { flex-wrap: wrap !important; } + .flex-md-nowrap { flex-wrap: nowrap !important; } + .flex-md-wrap-reverse { flex-wrap: wrap-reverse !important; } + .justify-content-md-start { justify-content: flex-start !important; } + .justify-content-md-end { justify-content: flex-end !important; } + .justify-content-md-center { justify-content: center !important; } + .justify-content-md-between { justify-content: space-between !important; } + .justify-content-md-around { justify-content: space-around !important; } + .justify-content-md-evenly { justify-content: space-evenly !important; } + .align-items-md-start { align-items: flex-start !important; } + .align-items-md-end { align-items: flex-end !important; } + .align-items-md-center { align-items: center !important; } + .align-items-md-baseline { align-items: baseline !important; } + .align-items-md-stretch { align-items: stretch !important; } + .align-content-md-start { align-content: flex-start !important; } + .align-content-md-end { align-content: flex-end !important; } + .align-content-md-center { align-content: center !important; } + .align-content-md-between { align-content: space-between !important; } + .align-content-md-around { align-content: space-around !important; } + .align-content-md-stretch { align-content: stretch !important; } + .align-self-md-auto { align-self: auto !important; } + .align-self-md-start { align-self: flex-start !important; } + .align-self-md-end { align-self: flex-end !important; } + .align-self-md-center { align-self: center !important; } + .align-self-md-baseline { align-self: baseline !important; } + .align-self-md-stretch { align-self: stretch !important; } + .order-md-first { order: -1 !important; } + .order-md-0 { order: 0 !important; } + .order-md-1 { order: 1 !important; } + .order-md-2 { order: 2 !important; } + .order-md-3 { order: 3 !important; } + .order-md-4 { order: 4 !important; } + .order-md-5 { order: 5 !important; } + .order-md-last { order: 6 !important; } + .m-md-0 { margin: 0 !important; } + .m-md-1 { margin: 0.25rem !important; } + .m-md-2 { margin: 0.5rem !important; } + .m-md-3 { margin: 1rem !important; } + .m-md-4 { margin: 1.5rem !important; } + .m-md-5 { margin: 3rem !important; } + .m-md-auto { margin: auto !important; } + .mx-md-0 { margin-right: 0 !important; margin-left: 0 !important; } + .mx-md-1 { margin-right: 0.25rem !important; margin-left: 0.25rem !important; } + .mx-md-2 { margin-right: 0.5rem !important; margin-left: 0.5rem !important; } + .mx-md-3 { margin-right: 1rem !important; margin-left: 1rem !important; } + .mx-md-4 { margin-right: 1.5rem !important; margin-left: 1.5rem !important; } + .mx-md-5 { margin-right: 3rem !important; margin-left: 3rem !important; } + .mx-md-auto { margin-right: auto !important; margin-left: auto !important; } + .my-md-0 { margin-top: 0 !important; margin-bottom: 0 !important; } + .my-md-1 { margin-top: 0.25rem !important; margin-bottom: 0.25rem !important; } + .my-md-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } + .my-md-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } + .my-md-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } + .my-md-5 { margin-top: 3rem !important; margin-bottom: 3rem !important; } + .my-md-auto { margin-top: auto !important; margin-bottom: auto !important; } + .mt-md-0 { margin-top: 0 !important; } + .mt-md-1 { margin-top: 0.25rem !important; } + .mt-md-2 { margin-top: 0.5rem !important; } + .mt-md-3 { margin-top: 1rem !important; } + .mt-md-4 { margin-top: 1.5rem !important; } + .mt-md-5 { margin-top: 3rem !important; } + .mt-md-auto { margin-top: auto !important; } + .me-md-0 { margin-right: 0 !important; } + .me-md-1 { margin-right: 0.25rem !important; } + .me-md-2 { margin-right: 0.5rem !important; } + .me-md-3 { margin-right: 1rem !important; } + .me-md-4 { margin-right: 1.5rem !important; } + .me-md-5 { margin-right: 3rem !important; } + .me-md-auto { margin-right: auto !important; } + .mb-md-0 { margin-bottom: 0 !important; } + .mb-md-1 { margin-bottom: 0.25rem !important; } + .mb-md-2 { margin-bottom: 0.5rem !important; } + .mb-md-3 { margin-bottom: 1rem !important; } + .mb-md-4 { margin-bottom: 1.5rem !important; } + .mb-md-5 { margin-bottom: 3rem !important; } + .mb-md-auto { margin-bottom: auto !important; } + .ms-md-0 { margin-left: 0 !important; } + .ms-md-1 { margin-left: 0.25rem !important; } + .ms-md-2 { margin-left: 0.5rem !important; } + .ms-md-3 { margin-left: 1rem !important; } + .ms-md-4 { margin-left: 1.5rem !important; } + .ms-md-5 { margin-left: 3rem !important; } + .ms-md-auto { margin-left: auto !important; } + .p-md-0 { padding: 0 !important; } + .p-md-1 { padding: 0.25rem !important; } + .p-md-2 { padding: 0.5rem !important; } + .p-md-3 { padding: 1rem !important; } + .p-md-4 { padding: 1.5rem !important; } + .p-md-5 { padding: 3rem !important; } + .px-md-0 { padding-right: 0 !important; padding-left: 0 !important; } + .px-md-1 { padding-right: 0.25rem !important; padding-left: 0.25rem !important; } + .px-md-2 { padding-right: 0.5rem !important; padding-left: 0.5rem !important; } + .px-md-3 { padding-right: 1rem !important; padding-left: 1rem !important; } + .px-md-4 { padding-right: 1.5rem !important; padding-left: 1.5rem !important; } + .px-md-5 { padding-right: 3rem !important; padding-left: 3rem !important; } + .py-md-0 { padding-top: 0 !important; padding-bottom: 0 !important; } + .py-md-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } + .py-md-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } + .py-md-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } + .py-md-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } + .py-md-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } + .pt-md-0 { padding-top: 0 !important; } + .pt-md-1 { padding-top: 0.25rem !important; } + .pt-md-2 { padding-top: 0.5rem !important; } + .pt-md-3 { padding-top: 1rem !important; } + .pt-md-4 { padding-top: 1.5rem !important; } + .pt-md-5 { padding-top: 3rem !important; } + .pe-md-0 { padding-right: 0 !important; } + .pe-md-1 { padding-right: 0.25rem !important; } + .pe-md-2 { padding-right: 0.5rem !important; } + .pe-md-3 { padding-right: 1rem !important; } + .pe-md-4 { padding-right: 1.5rem !important; } + .pe-md-5 { padding-right: 3rem !important; } + .pb-md-0 { padding-bottom: 0 !important; } + .pb-md-1 { padding-bottom: 0.25rem !important; } + .pb-md-2 { padding-bottom: 0.5rem !important; } + .pb-md-3 { padding-bottom: 1rem !important; } + .pb-md-4 { padding-bottom: 1.5rem !important; } + .pb-md-5 { padding-bottom: 3rem !important; } + .ps-md-0 { padding-left: 0 !important; } + .ps-md-1 { padding-left: 0.25rem !important; } + .ps-md-2 { padding-left: 0.5rem !important; } + .ps-md-3 { padding-left: 1rem !important; } + .ps-md-4 { padding-left: 1.5rem !important; } + .ps-md-5 { padding-left: 3rem !important; } + .gap-md-0 { gap: 0 !important; } + .gap-md-1 { gap: 0.25rem !important; } + .gap-md-2 { gap: 0.5rem !important; } + .gap-md-3 { gap: 1rem !important; } + .gap-md-4 { gap: 1.5rem !important; } + .gap-md-5 { gap: 3rem !important; } + .row-gap-md-0 { row-gap: 0 !important; } + .row-gap-md-1 { row-gap: 0.25rem !important; } + .row-gap-md-2 { row-gap: 0.5rem !important; } + .row-gap-md-3 { row-gap: 1rem !important; } + .row-gap-md-4 { row-gap: 1.5rem !important; } + .row-gap-md-5 { row-gap: 3rem !important; } + .column-gap-md-0 { column-gap: 0 !important; } + .column-gap-md-1 { column-gap: 0.25rem !important; } + .column-gap-md-2 { column-gap: 0.5rem !important; } + .column-gap-md-3 { column-gap: 1rem !important; } + .column-gap-md-4 { column-gap: 1.5rem !important; } + .column-gap-md-5 { column-gap: 3rem !important; } + .text-md-start { text-align: left !important; } + .text-md-end { text-align: right !important; } + .text-md-center { text-align: center !important; } } + @media (min-width: 992px) { .float-lg-start { float: left !important; } + .float-lg-end { float: right !important; } + .float-lg-none { float: none !important; } + .object-fit-lg-contain { object-fit: contain !important; } + .object-fit-lg-cover { object-fit: cover !important; } + .object-fit-lg-fill { object-fit: fill !important; } + .object-fit-lg-scale { object-fit: scale-down !important; } + .object-fit-lg-none { object-fit: none !important; } + .d-lg-inline { display: inline !important; } + .d-lg-inline-block { display: inline-block !important; } + .d-lg-block { display: block !important; } + .d-lg-grid { display: grid !important; } + .d-lg-inline-grid { display: inline-grid !important; } + .d-lg-table { display: table !important; } + .d-lg-table-row { display: table-row !important; } + .d-lg-table-cell { display: table-cell !important; } + .d-lg-flex { display: flex !important; } + .d-lg-inline-flex { display: inline-flex !important; } + .d-lg-none { display: none !important; } + .flex-lg-fill { flex: 1 1 auto !important; } + .flex-lg-row { flex-direction: row !important; } + .flex-lg-column { flex-direction: column !important; } + .flex-lg-row-reverse { flex-direction: row-reverse !important; } + .flex-lg-column-reverse { flex-direction: column-reverse !important; } + .flex-lg-grow-0 { flex-grow: 0 !important; } + .flex-lg-grow-1 { flex-grow: 1 !important; } + .flex-lg-shrink-0 { flex-shrink: 0 !important; } + .flex-lg-shrink-1 { flex-shrink: 1 !important; } + .flex-lg-wrap { flex-wrap: wrap !important; } + .flex-lg-nowrap { flex-wrap: nowrap !important; } + .flex-lg-wrap-reverse { flex-wrap: wrap-reverse !important; } + .justify-content-lg-start { justify-content: flex-start !important; } + .justify-content-lg-end { justify-content: flex-end !important; } + .justify-content-lg-center { justify-content: center !important; } + .justify-content-lg-between { justify-content: space-between !important; } + .justify-content-lg-around { justify-content: space-around !important; } + .justify-content-lg-evenly { justify-content: space-evenly !important; } + .align-items-lg-start { align-items: flex-start !important; } + .align-items-lg-end { align-items: flex-end !important; } + .align-items-lg-center { align-items: center !important; } + .align-items-lg-baseline { align-items: baseline !important; } + .align-items-lg-stretch { align-items: stretch !important; } + .align-content-lg-start { align-content: flex-start !important; } + .align-content-lg-end { align-content: flex-end !important; } + .align-content-lg-center { align-content: center !important; } + .align-content-lg-between { align-content: space-between !important; } + .align-content-lg-around { align-content: space-around !important; } + .align-content-lg-stretch { align-content: stretch !important; } + .align-self-lg-auto { align-self: auto !important; } + .align-self-lg-start { align-self: flex-start !important; } + .align-self-lg-end { align-self: flex-end !important; } + .align-self-lg-center { align-self: center !important; } + .align-self-lg-baseline { align-self: baseline !important; } + .align-self-lg-stretch { align-self: stretch !important; } + .order-lg-first { order: -1 !important; } + .order-lg-0 { order: 0 !important; } + .order-lg-1 { order: 1 !important; } + .order-lg-2 { order: 2 !important; } + .order-lg-3 { order: 3 !important; } + .order-lg-4 { order: 4 !important; } + .order-lg-5 { order: 5 !important; } + .order-lg-last { order: 6 !important; } + .m-lg-0 { margin: 0 !important; } + .m-lg-1 { margin: 0.25rem !important; } + .m-lg-2 { margin: 0.5rem !important; } + .m-lg-3 { margin: 1rem !important; } + .m-lg-4 { margin: 1.5rem !important; } + .m-lg-5 { margin: 3rem !important; } + .m-lg-auto { margin: auto !important; } + .mx-lg-0 { margin-right: 0 !important; margin-left: 0 !important; } + .mx-lg-1 { margin-right: 0.25rem !important; margin-left: 0.25rem !important; } + .mx-lg-2 { margin-right: 0.5rem !important; margin-left: 0.5rem !important; } + .mx-lg-3 { margin-right: 1rem !important; margin-left: 1rem !important; } + .mx-lg-4 { margin-right: 1.5rem !important; margin-left: 1.5rem !important; } + .mx-lg-5 { margin-right: 3rem !important; margin-left: 3rem !important; } + .mx-lg-auto { margin-right: auto !important; margin-left: auto !important; } + .my-lg-0 { margin-top: 0 !important; margin-bottom: 0 !important; } + .my-lg-1 { margin-top: 0.25rem !important; margin-bottom: 0.25rem !important; } + .my-lg-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } + .my-lg-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } + .my-lg-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } + .my-lg-5 { margin-top: 3rem !important; margin-bottom: 3rem !important; } + .my-lg-auto { margin-top: auto !important; margin-bottom: auto !important; } + .mt-lg-0 { margin-top: 0 !important; } + .mt-lg-1 { margin-top: 0.25rem !important; } + .mt-lg-2 { margin-top: 0.5rem !important; } + .mt-lg-3 { margin-top: 1rem !important; } + .mt-lg-4 { margin-top: 1.5rem !important; } + .mt-lg-5 { margin-top: 3rem !important; } + .mt-lg-auto { margin-top: auto !important; } + .me-lg-0 { margin-right: 0 !important; } + .me-lg-1 { margin-right: 0.25rem !important; } + .me-lg-2 { margin-right: 0.5rem !important; } + .me-lg-3 { margin-right: 1rem !important; } + .me-lg-4 { margin-right: 1.5rem !important; } + .me-lg-5 { margin-right: 3rem !important; } + .me-lg-auto { margin-right: auto !important; } + .mb-lg-0 { margin-bottom: 0 !important; } + .mb-lg-1 { margin-bottom: 0.25rem !important; } + .mb-lg-2 { margin-bottom: 0.5rem !important; } + .mb-lg-3 { margin-bottom: 1rem !important; } + .mb-lg-4 { margin-bottom: 1.5rem !important; } + .mb-lg-5 { margin-bottom: 3rem !important; } + .mb-lg-auto { margin-bottom: auto !important; } + .ms-lg-0 { margin-left: 0 !important; } + .ms-lg-1 { margin-left: 0.25rem !important; } + .ms-lg-2 { margin-left: 0.5rem !important; } + .ms-lg-3 { margin-left: 1rem !important; } + .ms-lg-4 { margin-left: 1.5rem !important; } + .ms-lg-5 { margin-left: 3rem !important; } + .ms-lg-auto { margin-left: auto !important; } + .p-lg-0 { padding: 0 !important; } + .p-lg-1 { padding: 0.25rem !important; } + .p-lg-2 { padding: 0.5rem !important; } + .p-lg-3 { padding: 1rem !important; } + .p-lg-4 { padding: 1.5rem !important; } + .p-lg-5 { padding: 3rem !important; } + .px-lg-0 { padding-right: 0 !important; padding-left: 0 !important; } + .px-lg-1 { padding-right: 0.25rem !important; padding-left: 0.25rem !important; } + .px-lg-2 { padding-right: 0.5rem !important; padding-left: 0.5rem !important; } + .px-lg-3 { padding-right: 1rem !important; padding-left: 1rem !important; } + .px-lg-4 { padding-right: 1.5rem !important; padding-left: 1.5rem !important; } + .px-lg-5 { padding-right: 3rem !important; padding-left: 3rem !important; } + .py-lg-0 { padding-top: 0 !important; padding-bottom: 0 !important; } + .py-lg-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } + .py-lg-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } + .py-lg-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } + .py-lg-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } + .py-lg-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } + .pt-lg-0 { padding-top: 0 !important; } + .pt-lg-1 { padding-top: 0.25rem !important; } + .pt-lg-2 { padding-top: 0.5rem !important; } + .pt-lg-3 { padding-top: 1rem !important; } + .pt-lg-4 { padding-top: 1.5rem !important; } + .pt-lg-5 { padding-top: 3rem !important; } + .pe-lg-0 { padding-right: 0 !important; } + .pe-lg-1 { padding-right: 0.25rem !important; } + .pe-lg-2 { padding-right: 0.5rem !important; } + .pe-lg-3 { padding-right: 1rem !important; } + .pe-lg-4 { padding-right: 1.5rem !important; } + .pe-lg-5 { padding-right: 3rem !important; } + .pb-lg-0 { padding-bottom: 0 !important; } + .pb-lg-1 { padding-bottom: 0.25rem !important; } + .pb-lg-2 { padding-bottom: 0.5rem !important; } + .pb-lg-3 { padding-bottom: 1rem !important; } + .pb-lg-4 { padding-bottom: 1.5rem !important; } + .pb-lg-5 { padding-bottom: 3rem !important; } + .ps-lg-0 { padding-left: 0 !important; } + .ps-lg-1 { padding-left: 0.25rem !important; } + .ps-lg-2 { padding-left: 0.5rem !important; } + .ps-lg-3 { padding-left: 1rem !important; } + .ps-lg-4 { padding-left: 1.5rem !important; } + .ps-lg-5 { padding-left: 3rem !important; } + .gap-lg-0 { gap: 0 !important; } + .gap-lg-1 { gap: 0.25rem !important; } + .gap-lg-2 { gap: 0.5rem !important; } + .gap-lg-3 { gap: 1rem !important; } + .gap-lg-4 { gap: 1.5rem !important; } + .gap-lg-5 { gap: 3rem !important; } + .row-gap-lg-0 { row-gap: 0 !important; } + .row-gap-lg-1 { row-gap: 0.25rem !important; } + .row-gap-lg-2 { row-gap: 0.5rem !important; } + .row-gap-lg-3 { row-gap: 1rem !important; } + .row-gap-lg-4 { row-gap: 1.5rem !important; } + .row-gap-lg-5 { row-gap: 3rem !important; } + .column-gap-lg-0 { column-gap: 0 !important; } + .column-gap-lg-1 { column-gap: 0.25rem !important; } + .column-gap-lg-2 { column-gap: 0.5rem !important; } + .column-gap-lg-3 { column-gap: 1rem !important; } + .column-gap-lg-4 { column-gap: 1.5rem !important; } + .column-gap-lg-5 { column-gap: 3rem !important; } + .text-lg-start { text-align: left !important; } + .text-lg-end { text-align: right !important; } + .text-lg-center { text-align: center !important; } } + @media (min-width: 1200px) { .float-xl-start { float: left !important; } + .float-xl-end { float: right !important; } + .float-xl-none { float: none !important; } + .object-fit-xl-contain { object-fit: contain !important; } + .object-fit-xl-cover { object-fit: cover !important; } + .object-fit-xl-fill { object-fit: fill !important; } + .object-fit-xl-scale { object-fit: scale-down !important; } + .object-fit-xl-none { object-fit: none !important; } + .d-xl-inline { display: inline !important; } + .d-xl-inline-block { display: inline-block !important; } + .d-xl-block { display: block !important; } + .d-xl-grid { display: grid !important; } + .d-xl-inline-grid { display: inline-grid !important; } + .d-xl-table { display: table !important; } + .d-xl-table-row { display: table-row !important; } + .d-xl-table-cell { display: table-cell !important; } + .d-xl-flex { display: flex !important; } + .d-xl-inline-flex { display: inline-flex !important; } + .d-xl-none { display: none !important; } + .flex-xl-fill { flex: 1 1 auto !important; } + .flex-xl-row { flex-direction: row !important; } + .flex-xl-column { flex-direction: column !important; } + .flex-xl-row-reverse { flex-direction: row-reverse !important; } + .flex-xl-column-reverse { flex-direction: column-reverse !important; } + .flex-xl-grow-0 { flex-grow: 0 !important; } + .flex-xl-grow-1 { flex-grow: 1 !important; } + .flex-xl-shrink-0 { flex-shrink: 0 !important; } + .flex-xl-shrink-1 { flex-shrink: 1 !important; } + .flex-xl-wrap { flex-wrap: wrap !important; } + .flex-xl-nowrap { flex-wrap: nowrap !important; } + .flex-xl-wrap-reverse { flex-wrap: wrap-reverse !important; } + .justify-content-xl-start { justify-content: flex-start !important; } + .justify-content-xl-end { justify-content: flex-end !important; } + .justify-content-xl-center { justify-content: center !important; } + .justify-content-xl-between { justify-content: space-between !important; } + .justify-content-xl-around { justify-content: space-around !important; } + .justify-content-xl-evenly { justify-content: space-evenly !important; } + .align-items-xl-start { align-items: flex-start !important; } + .align-items-xl-end { align-items: flex-end !important; } + .align-items-xl-center { align-items: center !important; } + .align-items-xl-baseline { align-items: baseline !important; } + .align-items-xl-stretch { align-items: stretch !important; } + .align-content-xl-start { align-content: flex-start !important; } + .align-content-xl-end { align-content: flex-end !important; } + .align-content-xl-center { align-content: center !important; } + .align-content-xl-between { align-content: space-between !important; } + .align-content-xl-around { align-content: space-around !important; } + .align-content-xl-stretch { align-content: stretch !important; } + .align-self-xl-auto { align-self: auto !important; } + .align-self-xl-start { align-self: flex-start !important; } + .align-self-xl-end { align-self: flex-end !important; } + .align-self-xl-center { align-self: center !important; } + .align-self-xl-baseline { align-self: baseline !important; } + .align-self-xl-stretch { align-self: stretch !important; } + .order-xl-first { order: -1 !important; } + .order-xl-0 { order: 0 !important; } + .order-xl-1 { order: 1 !important; } + .order-xl-2 { order: 2 !important; } + .order-xl-3 { order: 3 !important; } + .order-xl-4 { order: 4 !important; } + .order-xl-5 { order: 5 !important; } + .order-xl-last { order: 6 !important; } + .m-xl-0 { margin: 0 !important; } + .m-xl-1 { margin: 0.25rem !important; } + .m-xl-2 { margin: 0.5rem !important; } + .m-xl-3 { margin: 1rem !important; } + .m-xl-4 { margin: 1.5rem !important; } + .m-xl-5 { margin: 3rem !important; } + .m-xl-auto { margin: auto !important; } + .mx-xl-0 { margin-right: 0 !important; margin-left: 0 !important; } + .mx-xl-1 { margin-right: 0.25rem !important; margin-left: 0.25rem !important; } + .mx-xl-2 { margin-right: 0.5rem !important; margin-left: 0.5rem !important; } + .mx-xl-3 { margin-right: 1rem !important; margin-left: 1rem !important; } + .mx-xl-4 { margin-right: 1.5rem !important; margin-left: 1.5rem !important; } + .mx-xl-5 { margin-right: 3rem !important; margin-left: 3rem !important; } + .mx-xl-auto { margin-right: auto !important; margin-left: auto !important; } + .my-xl-0 { margin-top: 0 !important; margin-bottom: 0 !important; } + .my-xl-1 { margin-top: 0.25rem !important; margin-bottom: 0.25rem !important; } + .my-xl-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } + .my-xl-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } + .my-xl-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } + .my-xl-5 { margin-top: 3rem !important; margin-bottom: 3rem !important; } + .my-xl-auto { margin-top: auto !important; margin-bottom: auto !important; } + .mt-xl-0 { margin-top: 0 !important; } + .mt-xl-1 { margin-top: 0.25rem !important; } + .mt-xl-2 { margin-top: 0.5rem !important; } + .mt-xl-3 { margin-top: 1rem !important; } + .mt-xl-4 { margin-top: 1.5rem !important; } + .mt-xl-5 { margin-top: 3rem !important; } + .mt-xl-auto { margin-top: auto !important; } + .me-xl-0 { margin-right: 0 !important; } + .me-xl-1 { margin-right: 0.25rem !important; } + .me-xl-2 { margin-right: 0.5rem !important; } + .me-xl-3 { margin-right: 1rem !important; } + .me-xl-4 { margin-right: 1.5rem !important; } + .me-xl-5 { margin-right: 3rem !important; } + .me-xl-auto { margin-right: auto !important; } + .mb-xl-0 { margin-bottom: 0 !important; } + .mb-xl-1 { margin-bottom: 0.25rem !important; } + .mb-xl-2 { margin-bottom: 0.5rem !important; } + .mb-xl-3 { margin-bottom: 1rem !important; } + .mb-xl-4 { margin-bottom: 1.5rem !important; } + .mb-xl-5 { margin-bottom: 3rem !important; } + .mb-xl-auto { margin-bottom: auto !important; } + .ms-xl-0 { margin-left: 0 !important; } + .ms-xl-1 { margin-left: 0.25rem !important; } + .ms-xl-2 { margin-left: 0.5rem !important; } + .ms-xl-3 { margin-left: 1rem !important; } + .ms-xl-4 { margin-left: 1.5rem !important; } + .ms-xl-5 { margin-left: 3rem !important; } + .ms-xl-auto { margin-left: auto !important; } + .p-xl-0 { padding: 0 !important; } + .p-xl-1 { padding: 0.25rem !important; } + .p-xl-2 { padding: 0.5rem !important; } + .p-xl-3 { padding: 1rem !important; } + .p-xl-4 { padding: 1.5rem !important; } + .p-xl-5 { padding: 3rem !important; } + .px-xl-0 { padding-right: 0 !important; padding-left: 0 !important; } + .px-xl-1 { padding-right: 0.25rem !important; padding-left: 0.25rem !important; } + .px-xl-2 { padding-right: 0.5rem !important; padding-left: 0.5rem !important; } + .px-xl-3 { padding-right: 1rem !important; padding-left: 1rem !important; } + .px-xl-4 { padding-right: 1.5rem !important; padding-left: 1.5rem !important; } + .px-xl-5 { padding-right: 3rem !important; padding-left: 3rem !important; } + .py-xl-0 { padding-top: 0 !important; padding-bottom: 0 !important; } + .py-xl-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } + .py-xl-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } + .py-xl-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } + .py-xl-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } + .py-xl-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } + .pt-xl-0 { padding-top: 0 !important; } + .pt-xl-1 { padding-top: 0.25rem !important; } + .pt-xl-2 { padding-top: 0.5rem !important; } + .pt-xl-3 { padding-top: 1rem !important; } + .pt-xl-4 { padding-top: 1.5rem !important; } + .pt-xl-5 { padding-top: 3rem !important; } + .pe-xl-0 { padding-right: 0 !important; } + .pe-xl-1 { padding-right: 0.25rem !important; } + .pe-xl-2 { padding-right: 0.5rem !important; } + .pe-xl-3 { padding-right: 1rem !important; } + .pe-xl-4 { padding-right: 1.5rem !important; } + .pe-xl-5 { padding-right: 3rem !important; } + .pb-xl-0 { padding-bottom: 0 !important; } + .pb-xl-1 { padding-bottom: 0.25rem !important; } + .pb-xl-2 { padding-bottom: 0.5rem !important; } + .pb-xl-3 { padding-bottom: 1rem !important; } + .pb-xl-4 { padding-bottom: 1.5rem !important; } + .pb-xl-5 { padding-bottom: 3rem !important; } + .ps-xl-0 { padding-left: 0 !important; } + .ps-xl-1 { padding-left: 0.25rem !important; } + .ps-xl-2 { padding-left: 0.5rem !important; } + .ps-xl-3 { padding-left: 1rem !important; } + .ps-xl-4 { padding-left: 1.5rem !important; } + .ps-xl-5 { padding-left: 3rem !important; } + .gap-xl-0 { gap: 0 !important; } + .gap-xl-1 { gap: 0.25rem !important; } + .gap-xl-2 { gap: 0.5rem !important; } + .gap-xl-3 { gap: 1rem !important; } + .gap-xl-4 { gap: 1.5rem !important; } + .gap-xl-5 { gap: 3rem !important; } + .row-gap-xl-0 { row-gap: 0 !important; } + .row-gap-xl-1 { row-gap: 0.25rem !important; } + .row-gap-xl-2 { row-gap: 0.5rem !important; } + .row-gap-xl-3 { row-gap: 1rem !important; } + .row-gap-xl-4 { row-gap: 1.5rem !important; } + .row-gap-xl-5 { row-gap: 3rem !important; } + .column-gap-xl-0 { column-gap: 0 !important; } + .column-gap-xl-1 { column-gap: 0.25rem !important; } + .column-gap-xl-2 { column-gap: 0.5rem !important; } + .column-gap-xl-3 { column-gap: 1rem !important; } + .column-gap-xl-4 { column-gap: 1.5rem !important; } + .column-gap-xl-5 { column-gap: 3rem !important; } + .text-xl-start { text-align: left !important; } + .text-xl-end { text-align: right !important; } + .text-xl-center { text-align: center !important; } } + @media (min-width: 1400px) { .float-xxl-start { float: left !important; } + .float-xxl-end { float: right !important; } + .float-xxl-none { float: none !important; } + .object-fit-xxl-contain { object-fit: contain !important; } + .object-fit-xxl-cover { object-fit: cover !important; } + .object-fit-xxl-fill { object-fit: fill !important; } + .object-fit-xxl-scale { object-fit: scale-down !important; } + .object-fit-xxl-none { object-fit: none !important; } + .d-xxl-inline { display: inline !important; } + .d-xxl-inline-block { display: inline-block !important; } + .d-xxl-block { display: block !important; } + .d-xxl-grid { display: grid !important; } + .d-xxl-inline-grid { display: inline-grid !important; } + .d-xxl-table { display: table !important; } + .d-xxl-table-row { display: table-row !important; } + .d-xxl-table-cell { display: table-cell !important; } + .d-xxl-flex { display: flex !important; } + .d-xxl-inline-flex { display: inline-flex !important; } + .d-xxl-none { display: none !important; } + .flex-xxl-fill { flex: 1 1 auto !important; } + .flex-xxl-row { flex-direction: row !important; } + .flex-xxl-column { flex-direction: column !important; } + .flex-xxl-row-reverse { flex-direction: row-reverse !important; } + .flex-xxl-column-reverse { flex-direction: column-reverse !important; } + .flex-xxl-grow-0 { flex-grow: 0 !important; } + .flex-xxl-grow-1 { flex-grow: 1 !important; } + .flex-xxl-shrink-0 { flex-shrink: 0 !important; } + .flex-xxl-shrink-1 { flex-shrink: 1 !important; } + .flex-xxl-wrap { flex-wrap: wrap !important; } + .flex-xxl-nowrap { flex-wrap: nowrap !important; } + .flex-xxl-wrap-reverse { flex-wrap: wrap-reverse !important; } + .justify-content-xxl-start { justify-content: flex-start !important; } + .justify-content-xxl-end { justify-content: flex-end !important; } + .justify-content-xxl-center { justify-content: center !important; } + .justify-content-xxl-between { justify-content: space-between !important; } + .justify-content-xxl-around { justify-content: space-around !important; } + .justify-content-xxl-evenly { justify-content: space-evenly !important; } + .align-items-xxl-start { align-items: flex-start !important; } + .align-items-xxl-end { align-items: flex-end !important; } + .align-items-xxl-center { align-items: center !important; } + .align-items-xxl-baseline { align-items: baseline !important; } + .align-items-xxl-stretch { align-items: stretch !important; } + .align-content-xxl-start { align-content: flex-start !important; } + .align-content-xxl-end { align-content: flex-end !important; } + .align-content-xxl-center { align-content: center !important; } + .align-content-xxl-between { align-content: space-between !important; } + .align-content-xxl-around { align-content: space-around !important; } + .align-content-xxl-stretch { align-content: stretch !important; } + .align-self-xxl-auto { align-self: auto !important; } + .align-self-xxl-start { align-self: flex-start !important; } + .align-self-xxl-end { align-self: flex-end !important; } + .align-self-xxl-center { align-self: center !important; } + .align-self-xxl-baseline { align-self: baseline !important; } + .align-self-xxl-stretch { align-self: stretch !important; } + .order-xxl-first { order: -1 !important; } + .order-xxl-0 { order: 0 !important; } + .order-xxl-1 { order: 1 !important; } + .order-xxl-2 { order: 2 !important; } + .order-xxl-3 { order: 3 !important; } + .order-xxl-4 { order: 4 !important; } + .order-xxl-5 { order: 5 !important; } + .order-xxl-last { order: 6 !important; } + .m-xxl-0 { margin: 0 !important; } + .m-xxl-1 { margin: 0.25rem !important; } + .m-xxl-2 { margin: 0.5rem !important; } + .m-xxl-3 { margin: 1rem !important; } + .m-xxl-4 { margin: 1.5rem !important; } + .m-xxl-5 { margin: 3rem !important; } + .m-xxl-auto { margin: auto !important; } + .mx-xxl-0 { margin-right: 0 !important; margin-left: 0 !important; } + .mx-xxl-1 { margin-right: 0.25rem !important; margin-left: 0.25rem !important; } + .mx-xxl-2 { margin-right: 0.5rem !important; margin-left: 0.5rem !important; } + .mx-xxl-3 { margin-right: 1rem !important; margin-left: 1rem !important; } + .mx-xxl-4 { margin-right: 1.5rem !important; margin-left: 1.5rem !important; } + .mx-xxl-5 { margin-right: 3rem !important; margin-left: 3rem !important; } + .mx-xxl-auto { margin-right: auto !important; margin-left: auto !important; } + .my-xxl-0 { margin-top: 0 !important; margin-bottom: 0 !important; } + .my-xxl-1 { margin-top: 0.25rem !important; margin-bottom: 0.25rem !important; } + .my-xxl-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } + .my-xxl-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } + .my-xxl-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } + .my-xxl-5 { margin-top: 3rem !important; margin-bottom: 3rem !important; } + .my-xxl-auto { margin-top: auto !important; margin-bottom: auto !important; } + .mt-xxl-0 { margin-top: 0 !important; } + .mt-xxl-1 { margin-top: 0.25rem !important; } + .mt-xxl-2 { margin-top: 0.5rem !important; } + .mt-xxl-3 { margin-top: 1rem !important; } + .mt-xxl-4 { margin-top: 1.5rem !important; } + .mt-xxl-5 { margin-top: 3rem !important; } + .mt-xxl-auto { margin-top: auto !important; } + .me-xxl-0 { margin-right: 0 !important; } + .me-xxl-1 { margin-right: 0.25rem !important; } + .me-xxl-2 { margin-right: 0.5rem !important; } + .me-xxl-3 { margin-right: 1rem !important; } + .me-xxl-4 { margin-right: 1.5rem !important; } + .me-xxl-5 { margin-right: 3rem !important; } + .me-xxl-auto { margin-right: auto !important; } + .mb-xxl-0 { margin-bottom: 0 !important; } + .mb-xxl-1 { margin-bottom: 0.25rem !important; } + .mb-xxl-2 { margin-bottom: 0.5rem !important; } + .mb-xxl-3 { margin-bottom: 1rem !important; } + .mb-xxl-4 { margin-bottom: 1.5rem !important; } + .mb-xxl-5 { margin-bottom: 3rem !important; } + .mb-xxl-auto { margin-bottom: auto !important; } + .ms-xxl-0 { margin-left: 0 !important; } + .ms-xxl-1 { margin-left: 0.25rem !important; } + .ms-xxl-2 { margin-left: 0.5rem !important; } + .ms-xxl-3 { margin-left: 1rem !important; } + .ms-xxl-4 { margin-left: 1.5rem !important; } + .ms-xxl-5 { margin-left: 3rem !important; } + .ms-xxl-auto { margin-left: auto !important; } + .p-xxl-0 { padding: 0 !important; } + .p-xxl-1 { padding: 0.25rem !important; } + .p-xxl-2 { padding: 0.5rem !important; } + .p-xxl-3 { padding: 1rem !important; } + .p-xxl-4 { padding: 1.5rem !important; } + .p-xxl-5 { padding: 3rem !important; } + .px-xxl-0 { padding-right: 0 !important; padding-left: 0 !important; } + .px-xxl-1 { padding-right: 0.25rem !important; padding-left: 0.25rem !important; } + .px-xxl-2 { padding-right: 0.5rem !important; padding-left: 0.5rem !important; } + .px-xxl-3 { padding-right: 1rem !important; padding-left: 1rem !important; } + .px-xxl-4 { padding-right: 1.5rem !important; padding-left: 1.5rem !important; } + .px-xxl-5 { padding-right: 3rem !important; padding-left: 3rem !important; } + .py-xxl-0 { padding-top: 0 !important; padding-bottom: 0 !important; } + .py-xxl-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } + .py-xxl-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } + .py-xxl-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } + .py-xxl-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } + .py-xxl-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } + .pt-xxl-0 { padding-top: 0 !important; } + .pt-xxl-1 { padding-top: 0.25rem !important; } + .pt-xxl-2 { padding-top: 0.5rem !important; } + .pt-xxl-3 { padding-top: 1rem !important; } + .pt-xxl-4 { padding-top: 1.5rem !important; } + .pt-xxl-5 { padding-top: 3rem !important; } + .pe-xxl-0 { padding-right: 0 !important; } + .pe-xxl-1 { padding-right: 0.25rem !important; } + .pe-xxl-2 { padding-right: 0.5rem !important; } + .pe-xxl-3 { padding-right: 1rem !important; } + .pe-xxl-4 { padding-right: 1.5rem !important; } + .pe-xxl-5 { padding-right: 3rem !important; } + .pb-xxl-0 { padding-bottom: 0 !important; } + .pb-xxl-1 { padding-bottom: 0.25rem !important; } + .pb-xxl-2 { padding-bottom: 0.5rem !important; } + .pb-xxl-3 { padding-bottom: 1rem !important; } + .pb-xxl-4 { padding-bottom: 1.5rem !important; } + .pb-xxl-5 { padding-bottom: 3rem !important; } + .ps-xxl-0 { padding-left: 0 !important; } + .ps-xxl-1 { padding-left: 0.25rem !important; } + .ps-xxl-2 { padding-left: 0.5rem !important; } + .ps-xxl-3 { padding-left: 1rem !important; } + .ps-xxl-4 { padding-left: 1.5rem !important; } + .ps-xxl-5 { padding-left: 3rem !important; } + .gap-xxl-0 { gap: 0 !important; } + .gap-xxl-1 { gap: 0.25rem !important; } + .gap-xxl-2 { gap: 0.5rem !important; } + .gap-xxl-3 { gap: 1rem !important; } + .gap-xxl-4 { gap: 1.5rem !important; } + .gap-xxl-5 { gap: 3rem !important; } + .row-gap-xxl-0 { row-gap: 0 !important; } + .row-gap-xxl-1 { row-gap: 0.25rem !important; } + .row-gap-xxl-2 { row-gap: 0.5rem !important; } + .row-gap-xxl-3 { row-gap: 1rem !important; } + .row-gap-xxl-4 { row-gap: 1.5rem !important; } + .row-gap-xxl-5 { row-gap: 3rem !important; } + .column-gap-xxl-0 { column-gap: 0 !important; } + .column-gap-xxl-1 { column-gap: 0.25rem !important; } + .column-gap-xxl-2 { column-gap: 0.5rem !important; } + .column-gap-xxl-3 { column-gap: 1rem !important; } + .column-gap-xxl-4 { column-gap: 1.5rem !important; } + .column-gap-xxl-5 { column-gap: 3rem !important; } + .text-xxl-start { text-align: left !important; } + .text-xxl-end { text-align: right !important; } + .text-xxl-center { text-align: center !important; } } + @media (min-width: 1200px) { .fs-1 { font-size: 2.5rem !important; } + .fs-2 { font-size: 2rem !important; } + .fs-3 { font-size: 1.75rem !important; } + .fs-4 { font-size: 1.5rem !important; } } + @media print { .d-print-inline { display: inline !important; } + .d-print-inline-block { display: inline-block !important; } + .d-print-block { display: block !important; } + .d-print-grid { display: grid !important; } + .d-print-inline-grid { display: inline-grid !important; } + .d-print-table { display: table !important; } + .d-print-table-row { display: table-row !important; } + .d-print-table-cell { display: table-cell !important; } + .d-print-flex { display: flex !important; } + .d-print-inline-flex { display: inline-flex !important; } + .d-print-none { display: none !important; } } + /* TALAWA SCSS ----------- @@ -12385,6 +14067,7 @@ fieldset:disabled .btn { .btn-info { color: #fff; } + .btn-primary:hover, .btn-primary:active, .btn-secondary:hover, @@ -12416,20 +14099,24 @@ fieldset:disabled .btn { background-position-x: 1rem; } } + @keyframes spinner-border { to { transform: rotate(360deg) /* rtl:ignore */; } } + @keyframes spinner-grow { 0% { transform: scale(0); } + 50% { opacity: 1; transform: none; } } + /* 2. CONTENT @@ -12506,18 +14193,22 @@ input[type='file']::file-selector-button { 0% { background-position: -100% 0; } + 100% { background-position: 100% 0; } } + @keyframes shimmer { 0% { background-position: -1200px 0; } + 100% { background-position: 1200px 0; } } + /* 6. COLORS diff --git a/src/assets/images/bronze.png b/src/assets/images/bronze.png new file mode 100644 index 0000000000..e5b748a572 Binary files /dev/null and b/src/assets/images/bronze.png differ diff --git a/src/assets/images/gold.png b/src/assets/images/gold.png new file mode 100644 index 0000000000..cdbb0efdc4 Binary files /dev/null and b/src/assets/images/gold.png differ diff --git a/src/assets/images/silver.png b/src/assets/images/silver.png new file mode 100644 index 0000000000..b13d604de5 Binary files /dev/null and b/src/assets/images/silver.png differ diff --git a/src/assets/svgs/Attendance.svg b/src/assets/svgs/Attendance.svg new file mode 100644 index 0000000000..8dbc7b07ce --- /dev/null +++ b/src/assets/svgs/Attendance.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/components/AddOn/AddOn.test.tsx b/src/components/AddOn/AddOn.spec.tsx similarity index 70% rename from src/components/AddOn/AddOn.test.tsx rename to src/components/AddOn/AddOn.spec.tsx index 68475e8196..f0173c53fe 100644 --- a/src/components/AddOn/AddOn.test.tsx +++ b/src/components/AddOn/AddOn.spec.tsx @@ -1,16 +1,42 @@ +/** + * Unit tests for the AddOn component. + * + * This file contains tests for the AddOn component to ensure it behaves as expected + * under various scenarios. + */ import React from 'react'; import { render } from '@testing-library/react'; import { Provider } from 'react-redux'; import { BrowserRouter } from 'react-router-dom'; import { MockedProvider } from '@apollo/react-testing'; import { I18nextProvider } from 'react-i18next'; - +import '@testing-library/jest-dom'; +import { describe, test, expect, vi } from 'vitest'; import { store } from 'state/store'; + import AddOn from './AddOn'; import i18nForTest from 'utils/i18nForTest'; import { StaticMockLink } from 'utils/StaticMockLink'; + const link = new StaticMockLink([], true); -describe('Testing Addon component', () => { + +vi.mock('state/store', () => ({ + store: { + // Mock store configuration if needed + getState: vi.fn(), + subscribe: vi.fn(), + dispatch: vi.fn(), + }, +})); + +vi.mock('utils/i18nForTest', () => ({ + __esModule: true, + default: vi.fn(() => ({ + t: (key: string) => key, + })), +})); + +describe('Testing AddOn component', () => { const props = { children: 'This is a dummy text', }; diff --git a/src/components/AddOn/core/AddOnEntry/AddOnEntry.module.css b/src/components/AddOn/core/AddOnEntry/AddOnEntry.module.css deleted file mode 100644 index 1f1ea89996..0000000000 --- a/src/components/AddOn/core/AddOnEntry/AddOnEntry.module.css +++ /dev/null @@ -1,20 +0,0 @@ -.entrytoggle { - margin: 24px 24px 0 auto; - width: fit-content; -} - -.entryaction { - margin-left: auto; - display: flex !important; - align-items: center; -} - -.entryaction i { - margin-right: 8px; -} - -.entryaction .spinner-grow { - height: 1rem; - width: 1rem; - margin-right: 8px; -} diff --git a/src/components/AddOn/core/AddOnEntry/AddOnEntry.test.tsx b/src/components/AddOn/core/AddOnEntry/AddOnEntry.spec.tsx similarity index 83% rename from src/components/AddOn/core/AddOnEntry/AddOnEntry.test.tsx rename to src/components/AddOn/core/AddOnEntry/AddOnEntry.spec.tsx index 3d800eb59f..01ec40a917 100644 --- a/src/components/AddOn/core/AddOnEntry/AddOnEntry.test.tsx +++ b/src/components/AddOn/core/AddOnEntry/AddOnEntry.spec.tsx @@ -1,5 +1,12 @@ +/** + * Unit tests for the AddOnEntry component. + * + * This file contains tests for the AddOnEntry component to ensure it behaves as expected + * under various scenarios. + */ import React from 'react'; import { render, screen } from '@testing-library/react'; +import '@testing-library/jest-dom'; import { BrowserRouter } from 'react-router-dom'; import AddOnEntry from './AddOnEntry'; import { @@ -9,7 +16,7 @@ import { ApolloLink, HttpLink, } from '@apollo/client'; - +import { describe, test, vi, expect } from 'vitest'; import type { NormalizedCacheObject } from '@apollo/client'; import { Provider } from 'react-redux'; import { store } from 'state/store'; @@ -33,14 +40,15 @@ const httpLink = new HttpLink({ authorization: 'Bearer ' + getItem('token') || '', }, }); -console.error = jest.fn(); +console.error = vi.fn(); const client: ApolloClient = new ApolloClient({ cache: new InMemoryCache(), link: ApolloLink.from([httpLink]), }); let mockID: string | undefined = '1'; -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), + +vi.mock('react-router-dom', async () => ({ + ...(await vi.importActual('react-router-dom')), useParams: () => ({ orgId: mockID }), })); @@ -67,7 +75,7 @@ describe('Testing AddOnEntry', () => { - {} + @@ -77,8 +85,7 @@ describe('Testing AddOnEntry', () => { }); test('uses default values for title and description when not provided', () => { - // Render the component with only required parameters - const mockGetInstalledPlugins = jest.fn(); + const mockGetInstalledPlugins = vi.fn(); render( @@ -88,7 +95,7 @@ describe('Testing AddOnEntry', () => { id="123" createdBy="user1" uninstalledOrgs={['Org1']} - getInstalledPlugins={mockGetInstalledPlugins} // Providing an empty function + getInstalledPlugins={mockGetInstalledPlugins} /> @@ -96,13 +103,13 @@ describe('Testing AddOnEntry', () => { , ); - 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 + const titleElement = screen.getByText('No title provided'); + const descriptionElement = screen.getByText('Description not available'); + expect(titleElement).toBeInTheDocument(); + expect(descriptionElement).toBeInTheDocument(); }); - it('renders correctly', () => { + test('renders correctly', () => { const props = { id: '1', title: 'Test Addon', @@ -125,7 +132,7 @@ describe('Testing AddOnEntry', () => { - {} + @@ -137,7 +144,7 @@ describe('Testing AddOnEntry', () => { expect(getByText('Test User')).toBeInTheDocument(); }); - it('Uninstall Button works correctly', async () => { + test('Uninstall Button works correctly', async () => { const props = { id: '1', title: 'Test Addon', @@ -161,23 +168,21 @@ describe('Testing AddOnEntry', () => { - {} + , ); - await wait(100); - const btn = getByTestId('AddOnEntry_btn_install'); + + const btn = await getByTestId('AddOnEntry_btn_install'); await userEvent.click(btn); - await wait(100); expect(btn.innerHTML).toMatch(/Install/i); expect( await findByText('This feature is now removed from your organization'), ).toBeInTheDocument(); - await userEvent.click(btn); - await wait(100); + await userEvent.click(btn); expect(btn.innerHTML).toMatch(/Uninstall/i); expect( await findByText('This feature is now enabled in your organization'), @@ -217,20 +222,20 @@ describe('Testing AddOnEntry', () => { const btn = getByTestId('AddOnEntry_btn_install'); expect(btn.innerHTML).toMatch(/install/i); }); - test('should be redirected to /orglist if orgId is undefined', async () => { + + test('should redirect to /orglist if orgId is undefined', async () => { mockID = undefined; render( - {} + , ); - await wait(100); expect(window.location.pathname).toEqual('/orglist'); }); }); diff --git a/src/components/AddOn/core/AddOnEntry/AddOnEntry.tsx b/src/components/AddOn/core/AddOnEntry/AddOnEntry.tsx index 257917e2c2..e2971fee14 100644 --- a/src/components/AddOn/core/AddOnEntry/AddOnEntry.tsx +++ b/src/components/AddOn/core/AddOnEntry/AddOnEntry.tsx @@ -1,5 +1,5 @@ import React, { useState } from 'react'; -import styles from './AddOnEntry.module.css'; +import styles from './../../../../style/app.module.css'; import { Button, Card, Spinner } from 'react-bootstrap'; import { UPDATE_INSTALL_STATUS_PLUGIN_MUTATION } from 'GraphQl/Mutations/mutations'; import { useMutation } from '@apollo/client'; @@ -17,9 +17,9 @@ interface InterfaceAddOnEntryProps { description?: string; // Optional props createdBy: string; component?: string; // Optional props - modified?: any; // Optional props + modified?: boolean; // Optional props uninstalledOrgs: string[]; - getInstalledPlugins: () => any; + getInstalledPlugins: () => void; } /** @@ -59,6 +59,7 @@ function addOnEntry({ // Getting orgId from URL parameters const { orgId: currentOrg } = useParams(); + // console.log(currentOrg); if (!currentOrg) { // If orgId is not present in the URL, navigate to the org list page return ; @@ -101,7 +102,10 @@ function addOnEntry({ return ( <> - + {/* {uninstalledOrgs.includes(currentOrg) && ( )} */} - {title} + {title} {createdBy} @@ -134,7 +138,7 @@ function addOnEntry({ ) : ( )} {/* {installed ? 'Remove' : configurable ? 'Installed' : 'Install'} */} diff --git a/src/components/AddOn/core/AddOnRegister/AddOnRegister.test.tsx b/src/components/AddOn/core/AddOnRegister/AddOnRegister.spec.tsx similarity index 88% rename from src/components/AddOn/core/AddOnRegister/AddOnRegister.test.tsx rename to src/components/AddOn/core/AddOnRegister/AddOnRegister.spec.tsx index b04b450977..bbddef4fc7 100644 --- a/src/components/AddOn/core/AddOnRegister/AddOnRegister.test.tsx +++ b/src/components/AddOn/core/AddOnRegister/AddOnRegister.spec.tsx @@ -20,6 +20,7 @@ import i18nForTest from 'utils/i18nForTest'; import { I18nextProvider } from 'react-i18next'; import { toast } from 'react-toastify'; import useLocalStorage from 'utils/useLocalstorage'; +import { vi } from 'vitest'; const { getItem } = useLocalStorage(); @@ -74,26 +75,30 @@ const pluginData = { pluginDesc: 'Test Description', }; -jest.mock('react-toastify', () => ({ +vi.mock('react-toastify', () => ({ toast: { - success: jest.fn(), + success: vi.fn(), }, })); -const mockNavigate = jest.fn(); +const mockNavigate = vi.fn(); let mockId: string | undefined = 'id'; -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useParams: () => ({ orgId: mockId }), - useNavigate: () => mockNavigate, -})); + +vi.mock('react-router-dom', async () => { + const actual = await import('react-router-dom'); + return { + ...actual, + useParams: () => ({ orgId: mockId }), + useNavigate: () => mockNavigate, + }; +}); describe('Testing AddOnRegister', () => { const props = { id: '6234d8bf6ud937ddk70ecc5c9', }; - test('should render modal and take info to add plugin for registered organization', async () => { + it('should render modal and take info to add plugin for registered organization', async () => { await act(async () => { render( @@ -127,7 +132,7 @@ describe('Testing AddOnRegister', () => { ); }); - test('Expect toast.success to be called on successful plugin addition', async () => { + it('Expect toast.success to be called on successful plugin addition', async () => { await act(async () => { render( @@ -155,10 +160,10 @@ describe('Testing AddOnRegister', () => { userEvent.click(screen.getByTestId('addonregisterBtn')); await wait(100); - expect(toast.success).toBeCalledWith('Plugin added Successfully'); + expect(toast.success).toHaveBeenCalledWith('Plugin added Successfully'); }); - test('Expect the window to reload after successful plugin addition', async () => { + it('Expect the window to reload after successful plugin addition', async () => { await act(async () => { render( @@ -189,7 +194,7 @@ describe('Testing AddOnRegister', () => { expect(mockNavigate).toHaveBeenCalledWith(0); }); - test('should be redirected to /orglist if orgId is undefined', async () => { + it('should be redirected to /orglist if orgId is undefined', async () => { mockId = undefined; render( diff --git a/src/components/AddOn/core/AddOnRegister/AddOnRegister.tsx b/src/components/AddOn/core/AddOnRegister/AddOnRegister.tsx index 56ed6006c2..6023e74ee1 100644 --- a/src/components/AddOn/core/AddOnRegister/AddOnRegister.tsx +++ b/src/components/AddOn/core/AddOnRegister/AddOnRegister.tsx @@ -19,7 +19,7 @@ interface InterfaceFormStateTypes { installedOrgs: [string] | []; } -interface AddOnRegisterProps { +interface InterfaceAddOnRegisterProps { createdBy?: string; } @@ -37,7 +37,7 @@ interface AddOnRegisterProps { */ function addOnRegister({ createdBy = 'Admin', -}: AddOnRegisterProps): JSX.Element { +}: InterfaceAddOnRegisterProps): JSX.Element { // Translation hook for the 'addOnRegister' namespace const { t } = useTranslation('translation', { keyPrefix: 'addOnRegister' }); // Translation hook for the 'common' namespace diff --git a/src/components/AddOn/core/AddOnStore/AddOnStore.module.css b/src/components/AddOn/core/AddOnStore/AddOnStore.module.css index 8a34c03be5..9f5bb6c868 100644 --- a/src/components/AddOn/core/AddOnStore/AddOnStore.module.css +++ b/src/components/AddOn/core/AddOnStore/AddOnStore.module.css @@ -11,8 +11,12 @@ border-bottom: 3px solid #31bb6b; width: 15%; } - -.actioninput { +.input { + display: flex; + position: relative; + width: 560px; +} +/* .actioninput { text-decoration: none; margin-bottom: 50px; border-color: #e8e5e5; @@ -23,9 +27,46 @@ padding-right: 10px; padding-left: 10px; box-shadow: none; +} */ +.actioninput { + margin-top: 10px; + margin-bottom: 10px; + background-color: white; + box-shadow: 0 1px 1px #31bb6b; +} +.inputField > button { + padding-top: 10px; + padding-bottom: 10px; } .actionradio input { width: fit-content; margin: inherit; } +.cardGridItem { + width: 38vw; +} +.justifysp { + display: grid; + width: 100%; + justify-content: space-between; + align-items: baseline; + grid-template-rows: auto; + grid-template-columns: repeat(2, 1fr); + grid-gap: 0.8rem 0.4rem; +} + +@media screen and (max-width: 600px) { + .cardGridItem { + width: 100%; + } + .justifysp { + display: grid; + width: 100%; + justify-content: center; + align-items: start; + grid-template-rows: auto; + grid-template-columns: 1fr; + grid-gap: 0.8rem 0.4rem; + } +} diff --git a/src/components/AddOn/core/AddOnStore/AddOnStore.test.tsx b/src/components/AddOn/core/AddOnStore/AddOnStore.spec.tsx similarity index 71% rename from src/components/AddOn/core/AddOnStore/AddOnStore.test.tsx rename to src/components/AddOn/core/AddOnStore/AddOnStore.spec.tsx index e76e2a7b73..9a7eb08e1b 100644 --- a/src/components/AddOn/core/AddOnStore/AddOnStore.test.tsx +++ b/src/components/AddOn/core/AddOnStore/AddOnStore.spec.tsx @@ -1,5 +1,4 @@ import React, { act } from 'react'; -import 'jest-location-mock'; import { fireEvent, render, screen } from '@testing-library/react'; import { ApolloClient, @@ -20,13 +19,18 @@ import { ORGANIZATIONS_LIST, PLUGIN_GET } from 'GraphQl/Queries/Queries'; import userEvent from '@testing-library/user-event'; import useLocalStorage from 'utils/useLocalstorage'; import { MockedProvider } from '@apollo/react-testing'; +import { vi, describe, test, expect } from 'vitest'; const { getItem } = useLocalStorage(); - -jest.mock('components/AddOn/support/services/Plugin.helper', () => ({ +interface InterfacePlugin { + enabled: boolean; + pluginName: string; + component: string; +} +vi.mock('components/AddOn/support/services/Plugin.helper', () => ({ __esModule: true, - default: jest.fn().mockImplementation(() => ({ - fetchStore: jest.fn().mockResolvedValue([ + default: vi.fn().mockImplementation(() => ({ + fetchStore: vi.fn().mockResolvedValue([ { _id: '1', pluginName: 'Plugin 1', @@ -43,7 +47,7 @@ jest.mock('components/AddOn/support/services/Plugin.helper', () => ({ }, // Add more mock data as needed ]), - fetchInstalled: jest.fn().mockResolvedValue([ + fetchInstalled: vi.fn().mockResolvedValue([ { _id: '1', pluginName: 'Installed Plugin 1', @@ -60,10 +64,10 @@ jest.mock('components/AddOn/support/services/Plugin.helper', () => ({ }, // Add more mock data as needed ]), - generateLinks: jest.fn().mockImplementation((plugins) => { + generateLinks: vi.fn().mockImplementation((plugins: InterfacePlugin[]) => { return plugins - .filter((plugin: { enabled: any }) => plugin.enabled) - .map((installedPlugin: { pluginName: any; component: string }) => { + .filter((plugin) => plugin.enabled) + .map((installedPlugin) => { return { name: installedPlugin.pluginName, url: `/plugin/${installedPlugin.component.toLowerCase()}`, @@ -93,11 +97,11 @@ const client: ApolloClient = new ApolloClient({ link: ApolloLink.from([httpLink]), }); -jest.mock('components/AddOn/support/services/Plugin.helper', () => ({ +vi.mock('components/AddOn/support/services/Plugin.helper', () => ({ __esModule: true, - default: jest.fn().mockImplementation(() => ({ - fetchInstalled: jest.fn().mockResolvedValue([]), - fetchStore: jest.fn().mockResolvedValue([]), + default: vi.fn().mockImplementation(() => ({ + fetchInstalled: vi.fn().mockResolvedValue([]), + fetchStore: vi.fn().mockResolvedValue([]), })), })); @@ -162,10 +166,15 @@ const PLUGIN_LOADING_MOCK = { loading: true, }, }; -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useParams: () => ({ orgId: 'undefined' }), -})); + +vi.mock('react-router-dom', async () => { + const actualModule = await vi.importActual('react-router-dom'); + return { + ...actualModule, + useParams: () => ({ orgId: 'undefined' }), + }; +}); + const ORGANIZATIONS_LIST_MOCK = { request: { query: ORGANIZATIONS_LIST, @@ -301,77 +310,6 @@ describe('Testing AddOnStore Component', () => { expect(message.length).toBeGreaterThanOrEqual(1); }); - test('check filters enabled and disabled under Installed tab', async () => { - const mocks = [ORGANIZATIONS_LIST_MOCK, PLUGIN_GET_MOCK]; - render( - - - - - - - - - - - , - ); - - await wait(); - userEvent.click(screen.getByText('Installed')); - - expect(screen.getByText('Filters')).toBeInTheDocument(); - expect(screen.getByLabelText('Enabled')).toBeInTheDocument(); - expect(screen.getByLabelText('Disabled')).toBeInTheDocument(); - - fireEvent.click(screen.getByLabelText('Enabled')); - expect(screen.getByLabelText('Enabled')).toBeChecked(); - fireEvent.click(screen.getByLabelText('Disabled')); - expect(screen.getByLabelText('Disabled')).toBeChecked(); - }); - - test('check the working search bar when on Installed tab', async () => { - const mocks = [ORGANIZATIONS_LIST_MOCK, PLUGIN_GET_MOCK]; - - const { container } = render( - - - - - - - - - - - , - ); - await wait(); - userEvent.click(screen.getByText('Installed')); - - await wait(); - let searchText = ''; - fireEvent.change(screen.getByPlaceholderText('Ex: Donations'), { - target: { value: searchText }, - }); - expect(container).toHaveTextContent('Plugin 1'); - expect(container).toHaveTextContent('Plugin 3'); - - searchText = 'Plugin 1'; - fireEvent.change(screen.getByPlaceholderText('Ex: Donations'), { - target: { value: searchText }, - }); - const plugin1Elements = screen.queryAllByText('Plugin 1'); - expect(plugin1Elements.length).toBeGreaterThan(1); - - searchText = 'Test Plugin'; - fireEvent.change(screen.getByPlaceholderText('Ex: Donations'), { - target: { value: searchText }, - }); - const message = screen.getAllByText('Plugin does not exists'); - expect(message.length).toBeGreaterThanOrEqual(1); - }); - test('AddOnStore loading test', async () => { expect(true).toBe(true); const mocks = [ORGANIZATIONS_LIST_MOCK, PLUGIN_LOADING_MOCK]; diff --git a/src/components/AddOn/core/AddOnStore/AddOnStore.tsx b/src/components/AddOn/core/AddOnStore/AddOnStore.tsx index 878ad64e31..90a32d9bb3 100644 --- a/src/components/AddOn/core/AddOnStore/AddOnStore.tsx +++ b/src/components/AddOn/core/AddOnStore/AddOnStore.tsx @@ -1,16 +1,27 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ import React, { useState } from 'react'; -// import PropTypes from 'react'; import styles from './AddOnStore.module.css'; import AddOnEntry from '../AddOnEntry/AddOnEntry'; -import Action from '../../support/components/Action/Action'; import { useQuery } from '@apollo/client'; -import { PLUGIN_GET } from 'GraphQl/Queries/Queries'; // GraphQL query for fetching plugins -import { Col, Form, Row, Tab, Tabs } from 'react-bootstrap'; +import { PLUGIN_GET } from 'GraphQl/Queries/Queries'; // PLUGIN_LIST +import { Col, Dropdown, Form, Row, Tab, Tabs, Button } from 'react-bootstrap'; import PluginHelper from 'components/AddOn/support/services/Plugin.helper'; import { store } from './../../../../state/store'; import { useTranslation } from 'react-i18next'; import { useParams } from 'react-router-dom'; +import { Search } from '@mui/icons-material'; + +interface InterfacePluginHelper { + _id: string; + pluginName?: string; + pluginDesc?: string; + pluginCreatedBy: string; + pluginInstallStatus?: boolean; + uninstalledOrgs: string[]; + installed: boolean; + enabled: boolean; + name: string; + component: string; +} /** * Component for managing and displaying plugins in the store. @@ -30,12 +41,13 @@ function addOnStore(): JSX.Element { const [isStore, setIsStore] = useState(true); const [showEnabled, setShowEnabled] = useState(true); const [searchText, setSearchText] = useState(''); - const [, setDataList] = useState([]); + const [, setDataList] = useState([]); - // type plugData = { pluginName: String, plug }; - const { data, loading } = useQuery(PLUGIN_GET); + const { data, loading } = useQuery<{ getPlugins: InterfacePluginHelper[] }>( + PLUGIN_GET, + ); - const { orgId } = useParams(); + const { orgId } = useParams<{ orgId: string }>(); /** * Fetches store plugins and updates the Redux store with the plugin data. @@ -44,10 +56,10 @@ function addOnStore(): JSX.Element { const getStorePlugins = async (): Promise => { let plugins = await new PluginHelper().fetchStore(); const installIds = (await new PluginHelper().fetchInstalled()).map( - (plugin: any) => plugin.id, + (plugin: InterfacePluginHelper) => plugin._id, ); - plugins = plugins.map((plugin: any) => { - plugin.installed = installIds.includes(plugin.id); + plugins = plugins.map((plugin: InterfacePluginHelper) => { + plugin.installed = installIds.includes(plugin._id); return plugin; }); store.dispatch({ type: 'UPDATE_STORE', payload: plugins }); @@ -57,8 +69,8 @@ function addOnStore(): JSX.Element { * Sets the list of installed plugins in the component's state. */ /* istanbul ignore next */ - const getInstalledPlugins: () => any = () => { - setDataList(data); + const getInstalledPlugins: () => void = () => { + setDataList(data?.getPlugins ?? []); }; /** @@ -66,10 +78,14 @@ function addOnStore(): JSX.Element { * * @param tab - The key of the selected tab (either 'available' or 'installed'). */ - const updateSelectedTab = (tab: any): void => { + const updateSelectedTab = (tab: string): void => { setIsStore(tab === 'available'); /* istanbul ignore next */ - isStore ? getStorePlugins() : getInstalledPlugins(); + if (tab === 'available') { + getStorePlugins(); + } else { + getInstalledPlugins(); + } }; /** @@ -77,10 +93,23 @@ function addOnStore(): JSX.Element { * * @param ev - The event object from the filter change. */ - const filterChange = (ev: any): void => { + const filterChange = (ev: React.ChangeEvent): void => { setShowEnabled(ev.target.value === 'enabled'); }; + const filterPlugins = ( + plugins: InterfacePluginHelper[], + searchTerm: string, + ): InterfacePluginHelper[] => { + if (!searchTerm) { + return plugins; + } + + return plugins.filter((plugin) => + plugin.pluginName?.toLowerCase().includes(searchTerm.toLowerCase()), + ); + }; + // Show a loader while the data is being fetched /* istanbul ignore next */ if (loading) { @@ -93,9 +122,23 @@ function addOnStore(): JSX.Element { return ( <> - - - + + +
setSearchText(e.target.value)} /> - + +
{!isStore && ( - -
-
- - -
-
-
+ + filterChange( + e as unknown as React.ChangeEvent, + ) + } + > + + {showEnabled ? t('enable') : t('disable')} + + + + {t('enable')} + + + {t('disable')} + + + )} - -
-

{t('pHeading')}

- {searchText ? ( -

- Search results for {searchText} -

- ) : null} +
+ { + if (eventKey) { + updateSelectedTab(eventKey); + } + }} + > + +
+ {(() => { + const filteredPlugins = filterPlugins( + data?.getPlugins || [], + searchText, + ); - {t('pMessage')}; + } + + return ( +
+ {filteredPlugins.map((plug, i) => ( +
+ +
+ ))} +
+ ); + })()} +
+
+ - - {data.getPlugins.filter( - (val: { - _id: string; - pluginName: string | undefined; - pluginDesc: string | undefined; - pluginCreatedBy: string; - pluginInstallStatus: boolean | undefined; - getInstalledPlugins: () => any; - }) => { - if (searchText == '') { - return val; - } else if ( - val.pluginName - ?.toLowerCase() - .includes(searchText.toLowerCase()) - ) { - return val; - } - }, - ).length === 0 ? ( -

{t('pMessage')}

- ) : ( - data.getPlugins - .filter( - (val: { - _id: string; - pluginName: string | undefined; - pluginDesc: string | undefined; - pluginCreatedBy: string; - pluginInstallStatus: boolean | undefined; - getInstalledPlugins: () => any; - }) => { - if (searchText == '') { - return val; - } else if ( - val.pluginName - ?.toLowerCase() - .includes(searchText.toLowerCase()) - ) { - return val; - } - }, - ) - .map( - ( - plug: { - _id: string; - pluginName: string | undefined; - pluginDesc: string | undefined; - pluginCreatedBy: string; - uninstalledOrgs: string[]; - getInstalledPlugins: () => any; - }, - i: React.Key | null | undefined, - ): JSX.Element => ( - - ), - ) - )} -
- - {data.getPlugins - .filter( - (plugin: any) => !plugin.uninstalledOrgs.includes(orgId), - ) - .filter( - (val: { - _id: string; - pluginName: string | undefined; - pluginDesc: string | undefined; - pluginCreatedBy: string; - pluginInstallStatus: boolean | undefined; - getInstalledPlugins: () => any; - }) => { - if (searchText == '') { - return val; - } else if ( - val.pluginName - ?.toLowerCase() - .includes(searchText.toLowerCase()) - ) { - return val; - } - }, - ).length === 0 ? ( -

{t('pMessage')}

- ) : ( - data.getPlugins - .filter( - (plugin: any) => !plugin.uninstalledOrgs.includes(orgId), - ) - .filter( - (val: { - _id: string; - pluginName: string | undefined; - pluginDesc: string | undefined; - pluginCreatedBy: string; - pluginInstallStatus: boolean | undefined; - getInstalledPlugins: () => any; - }) => { - if (searchText == '') { - return val; - } else if ( - val.pluginName - ?.toLowerCase() - .includes(searchText.toLowerCase()) - ) { - return val; - } - }, - ) - .map( - ( - plug: { - _id: string; - pluginName: string | undefined; - pluginDesc: string | undefined; - pluginCreatedBy: string; - uninstalledOrgs: string[]; - pluginInstallStatus: boolean | undefined; - getInstalledPlugins: () => any; - }, - i: React.Key | null | undefined, - ): JSX.Element => ( - - ), - ) - )} -
-
-
- +
+ {(() => { + const installedPlugins = (data?.getPlugins || []).filter( + (plugin) => !plugin.uninstalledOrgs.includes(orgId ?? ''), + ); + const filteredPlugins = filterPlugins( + installedPlugins, + searchText, + ); + + if (filteredPlugins.length === 0) { + return

{t('pMessage')}

; + } + + return filteredPlugins.map((plug, i) => ( +
+ +
+ )); + })()} +
+ + +
); diff --git a/src/components/AddOn/support/components/Action/Action.test.tsx b/src/components/AddOn/support/components/Action/Action.spec.tsx similarity index 65% rename from src/components/AddOn/support/components/Action/Action.test.tsx rename to src/components/AddOn/support/components/Action/Action.spec.tsx index ce6cd633b9..e0682a5645 100644 --- a/src/components/AddOn/support/components/Action/Action.test.tsx +++ b/src/components/AddOn/support/components/Action/Action.spec.tsx @@ -1,6 +1,13 @@ +/** + * Unit tests for the Action component. + * + * This file contains tests for the Action component to ensure it behaves as expected + * under various scenarios. + */ import React from 'react'; import { render } from '@testing-library/react'; import { Provider } from 'react-redux'; +import { describe, test, expect } from 'vitest'; import { store } from 'state/store'; import Action from './Action'; @@ -11,7 +18,7 @@ describe('Testing Action Component', () => { label: 'dummy label', }; - test('should render props and text elements test for the page component', () => { + test('should render props and text elements for the page component', () => { const { getByText } = render( diff --git a/src/components/AddOn/support/components/MainContent/MainContent.test.tsx b/src/components/AddOn/support/components/MainContent/MainContent.spec.tsx similarity index 70% rename from src/components/AddOn/support/components/MainContent/MainContent.test.tsx rename to src/components/AddOn/support/components/MainContent/MainContent.spec.tsx index 81adbc916e..90988e8d2b 100644 --- a/src/components/AddOn/support/components/MainContent/MainContent.test.tsx +++ b/src/components/AddOn/support/components/MainContent/MainContent.spec.tsx @@ -1,5 +1,6 @@ import React from 'react'; import { render } from '@testing-library/react'; +import { describe, it, expect } from 'vitest'; import { Provider } from 'react-redux'; import { BrowserRouter } from 'react-router-dom'; @@ -11,7 +12,7 @@ describe('Testing MainContent component', () => { children: 'This is a dummy text', }; - test('should render props and children for the Main Content', () => { + it('should render props and children for the Main Content', () => { const { getByTestId, getByText } = render( @@ -20,7 +21,7 @@ describe('Testing MainContent component', () => { , ); - expect(getByTestId('mainContentCheck')).toBeInTheDocument(); - expect(getByText(props.children)).toBeInTheDocument(); + expect(getByTestId('mainContentCheck')).not.toBeNull(); + expect(getByText(props.children)).not.toBeNull(); }); }); diff --git a/src/components/AddOn/support/components/SidePanel/SidePanel.test.tsx b/src/components/AddOn/support/components/SidePanel/SidePanel.spec.tsx similarity index 82% rename from src/components/AddOn/support/components/SidePanel/SidePanel.test.tsx rename to src/components/AddOn/support/components/SidePanel/SidePanel.spec.tsx index d929278d0e..4a5f4e5692 100644 --- a/src/components/AddOn/support/components/SidePanel/SidePanel.test.tsx +++ b/src/components/AddOn/support/components/SidePanel/SidePanel.spec.tsx @@ -11,11 +11,16 @@ const client: ApolloClient = new ApolloClient({ }); describe('Testing Contribution Stats', () => { + /** + * Props to be passed to the `SidePanel` component during the test. + */ const props = { collapse: true, children: '234', }; - + /** + * Verifies that the `SidePanel` component renders correctly with given props. + */ test('should render props and text elements test for the SidePanel component', () => { render( diff --git a/src/components/AddOn/support/services/Plugin.helper.test.ts b/src/components/AddOn/support/services/Plugin.helper.spec.ts similarity index 53% rename from src/components/AddOn/support/services/Plugin.helper.test.ts rename to src/components/AddOn/support/services/Plugin.helper.spec.ts index e024734247..51c8ec4bc5 100644 --- a/src/components/AddOn/support/services/Plugin.helper.test.ts +++ b/src/components/AddOn/support/services/Plugin.helper.spec.ts @@ -1,15 +1,39 @@ import PluginHelper from './Plugin.helper'; +import { vi } from 'vitest'; + +/** + * This file contains unit tests for the PluginHelper component. + * + * The tests cover: + * - Verification that the class contains the required method definitions. + * - Correct functionality of the `generateLinks` method, including returning proper objects. + * - Proper behavior of the `fetchStore` method, including handling of mocked JSON responses. + * - Functionality of the `fetchInstalled` method, verifying it returns the expected JSON data. + * + * These tests use Vitest for test execution and mock the global `fetch` function for asynchronous tests. + */ describe('Testing src/components/AddOn/support/services/Plugin.helper.ts', () => { - test('Class should contain the required method definitions', () => { + it('Class should contain the required method definitions', () => { const pluginHelper = new PluginHelper(); expect(pluginHelper).toHaveProperty('fetchStore'); expect(pluginHelper).toHaveProperty('fetchInstalled'); expect(pluginHelper).toHaveProperty('generateLinks'); expect(pluginHelper).toHaveProperty('generateLinks'); }); - test('generateLinks should return proper objects', () => { - const obj = { enabled: true, name: 'demo', component: 'samplecomponent' }; + it('generateLinks should return proper objects', () => { + const obj = { + enabled: true, + name: 'demo', + component: 'samplecomponent', + _id: 'someId', + pluginName: 'pluginName', + pluginDesc: 'pluginDesc', + pluginCreatedBy: 'creator', + pluginInstallStatus: true, + uninstalledOrgs: ['org1', 'org2'], + installed: true, + }; const objToMatch = { name: 'demo', url: '/plugin/samplecomponent' }; const pluginHelper = new PluginHelper(); const val = pluginHelper.generateLinks([obj]); @@ -17,9 +41,9 @@ describe('Testing src/components/AddOn/support/services/Plugin.helper.ts', () => }); it('fetchStore should return expected JSON', async () => { const helper = new PluginHelper(); - const spy = jest.spyOn(global, 'fetch').mockImplementation(() => { + const spy = vi.spyOn(global, 'fetch').mockImplementation(() => { const response = new Response(); - response.json = jest + response.json = vi .fn() .mockReturnValue(Promise.resolve({ data: 'mock data' })); return Promise.resolve(response); @@ -35,11 +59,11 @@ describe('Testing src/components/AddOn/support/services/Plugin.helper.ts', () => { name: 'plugin1', component: 'Component1', enabled: true }, { name: 'plugin2', component: 'Component2', enabled: false }, ]; - jest.spyOn(global, 'fetch').mockImplementation(() => { + vi.spyOn(global, 'fetch').mockImplementation(() => { const response = new Response(); - response.json = jest.fn().mockReturnValue(Promise.resolve(mockResponse)); + response.json = vi.fn().mockReturnValue(Promise.resolve(mockResponse)); return Promise.resolve(response); - }) as jest.Mock; + }); const result = await pluginHelper.fetchInstalled(); expect(result).toEqual(mockResponse); }); diff --git a/src/components/AddPeopleToTag/AddPeopleToTag.module.css b/src/components/AddPeopleToTag/AddPeopleToTag.module.css new file mode 100644 index 0000000000..5dd04ffed5 --- /dev/null +++ b/src/components/AddPeopleToTag/AddPeopleToTag.module.css @@ -0,0 +1,54 @@ +.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 { + height: 100px; + overflow-y: auto; + margin-bottom: 1rem; +} + +.memberBadge { + display: flex; + align-items: center; + padding: 5px 10px; + border-radius: 12px; + box-shadow: 0 1px 3px var(--bs-gray-400); + max-width: calc(100% - 2rem); +} + +.removeFilterIcon { + cursor: pointer; +} + +.loadingDiv { + min-height: 300px; + display: flex; + justify-content: center; + align-items: center; +} diff --git a/src/components/AddPeopleToTag/AddPeopleToTag.test.tsx b/src/components/AddPeopleToTag/AddPeopleToTag.test.tsx new file mode 100644 index 0000000000..824bc25654 --- /dev/null +++ b/src/components/AddPeopleToTag/AddPeopleToTag.test.tsx @@ -0,0 +1,316 @@ +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 { InMemoryCache, 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'; +import type { TFunction } from 'i18next'; + +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]) as TFunction< + 'translation', + 'manageTag' + >, + tCommon: ((key: string) => translations[key]) as TFunction< + 'common', + undefined + >, +}; + +const cache = new InMemoryCache({ + typePolicies: { + Query: { + fields: { + getUserTag: { + merge(existing = {}, incoming) { + const merged = { + ...existing, + ...incoming, + usersToAssignTo: { + ...existing.usersToAssignTo, + ...incoming.usersToAssignTo, + edges: [ + ...(existing.usersToAssignTo?.edges || []), + ...(incoming.usersToAssignTo?.edges || []), + ], + }, + }; + + return merged; + }, + }, + }, + }, + }, +}); + +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('searchs for tags where the firstName matches the provided firstName search input', async () => { + renderAddPeopleToTagModal(props, link); + + await wait(); + + await waitFor(() => { + expect( + screen.getByPlaceholderText(translations.firstName), + ).toBeInTheDocument(); + }); + const input = screen.getByPlaceholderText(translations.firstName); + fireEvent.change(input, { target: { value: 'usersToAssignTo' } }); + + // should render the two users from the mock data + // where firstName starts with "usersToAssignTo" + await waitFor(() => { + const members = screen.getAllByTestId('memberName'); + expect(members.length).toEqual(2); + }); + + await waitFor(() => { + expect(screen.getAllByTestId('memberName')[0]).toHaveTextContent( + 'usersToAssignTo user1', + ); + }); + + await waitFor(() => { + expect(screen.getAllByTestId('memberName')[1]).toHaveTextContent( + 'usersToAssignTo user2', + ); + }); + }); + + test('searchs for tags where the lastName matches the provided lastName search input', async () => { + renderAddPeopleToTagModal(props, link); + + await wait(); + + await waitFor(() => { + expect( + screen.getByPlaceholderText(translations.lastName), + ).toBeInTheDocument(); + }); + const input = screen.getByPlaceholderText(translations.lastName); + fireEvent.change(input, { target: { value: 'userToAssignTo' } }); + + // should render the two users from the mock data + // where lastName starts with "usersToAssignTo" + await waitFor(() => { + const members = screen.getAllByTestId('memberName'); + expect(members.length).toEqual(2); + }); + + await waitFor(() => { + expect(screen.getAllByTestId('memberName')[0]).toHaveTextContent( + 'first userToAssignTo', + ); + }); + + await waitFor(() => { + expect(screen.getAllByTestId('memberName')[1]).toHaveTextContent( + 'second userToAssignTo', + ); + }); + }); + + 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 addPeopleToTagScrollableDiv = screen.getByTestId( + 'addPeopleToTagScrollableDiv', + ); + + const initialMemberDataLength = screen.getAllByTestId('memberName').length; + + // Set scroll position to the bottom + fireEvent.scroll(addPeopleToTagScrollableDiv, { + target: { scrollY: addPeopleToTagScrollableDiv.scrollHeight }, + }); + + await waitFor(() => { + const finalMemberDataLength = screen.getAllByTestId('memberName').length; + expect(finalMemberDataLength).toBeGreaterThan(initialMemberDataLength); + + expect(getByText(translations.addPeople)).toBeInTheDocument(); + }); + }); + + test('Toasts error when no one is selected while assigning', async () => { + renderAddPeopleToTagModal(props, link); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('assignPeopleBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('assignPeopleBtn')); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalledWith(translations.noOneSelected); + }); + }); + + test('Assigns tag to multiple people', async () => { + renderAddPeopleToTagModal(props, link); + + await wait(); + + // select members and assign them + 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..51d21a6a1c --- /dev/null +++ b/src/components/AddPeopleToTag/AddPeopleToTag.tsx @@ -0,0 +1,419 @@ +import { useMutation, useQuery } from '@apollo/client'; +import type { GridCellParams, GridColDef } from '@mui/x-data-grid'; +import { DataGrid } from '@mui/x-data-grid'; +import { USER_TAGS_MEMBERS_TO_ASSIGN_TO } from 'GraphQl/Queries/userTagQueries'; +import type { ChangeEvent } from 'react'; +import React, { useEffect, 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 type { InterfaceTagUsersToAssignToQuery } from 'utils/organizationTagsUtils'; +import { + TAGS_QUERY_DATA_CHUNK_SIZE, + 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'; +import InfiniteScrollLoader from 'components/InfiniteScrollLoader/InfiniteScrollLoader'; +import type { TFunction } from 'i18next'; + +/** + * Props for the `AddPeopleToTag` component. + */ +export interface InterfaceAddPeopleToTagProps { + addPeopleToTagModalIsOpen: boolean; + hideAddPeopleToTagModal: () => void; + refetchAssignedMembersData: () => void; + t: TFunction<'translation', 'manageTag'>; + tCommon: TFunction<'common', undefined>; +} + +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 [memberToAssignToSearchFirstName, setMemberToAssignToSearchFirstName] = + useState(''); + const [memberToAssignToSearchLastName, setMemberToAssignToSearchLastName] = + useState(''); + + const { + data: userTagsMembersToAssignToData, + loading: userTagsMembersToAssignToLoading, + error: userTagsMembersToAssignToError, + refetch: userTagsMembersToAssignToRefetch, + fetchMore: fetchMoreMembersToAssignTo, + }: InterfaceTagUsersToAssignToQuery = useQuery( + USER_TAGS_MEMBERS_TO_ASSIGN_TO, + { + variables: { + id: currentTagId, + first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { + firstName: { starts_with: memberToAssignToSearchFirstName }, + lastName: { starts_with: memberToAssignToSearchLastName }, + }, + }, + skip: !addPeopleToTagModalIsOpen, + }, + ); + + useEffect(() => { + setMemberToAssignToSearchFirstName(''); + setMemberToAssignToSearchLastName(''); + userTagsMembersToAssignToRefetch(); + }, [addPeopleToTagModalIsOpen]); + + const loadMoreMembersToAssignTo = (): void => { + fetchMoreMembersToAssignTo({ + variables: { + first: TAGS_QUERY_DATA_CHUNK_SIZE, + after: + userTagsMembersToAssignToData?.getUsersToAssignTo.usersToAssignTo + .pageInfo.endCursor, // Fetch after the last loaded cursor + }, + updateQuery: ( + prevResult: { + getUsersToAssignTo: InterfaceQueryUserTagsMembersToAssignTo; + }, + { + fetchMoreResult, + }: { + fetchMoreResult: { + getUsersToAssignTo: InterfaceQueryUserTagsMembersToAssignTo; + }; + }, + ) => { + if (!fetchMoreResult) /* istanbul ignore next */ return prevResult; + + return { + getUsersToAssignTo: { + ...fetchMoreResult.getUsersToAssignTo, + usersToAssignTo: { + ...fetchMoreResult.getUsersToAssignTo.usersToAssignTo, + edges: [ + ...prevResult.getUsersToAssignTo.usersToAssignTo.edges, + ...fetchMoreResult.getUsersToAssignTo.usersToAssignTo.edges, + ], + }, + }, + }; + }, + }); + }; + + const userTagMembersToAssignTo = + userTagsMembersToAssignToData?.getUsersToAssignTo.usersToAssignTo.edges.map( + (edge) => edge.node, + ) ?? /* istanbul ignore next */ []; + + 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(); + + if (!assignToMembers.length) { + toast.error(t('noOneSelected')); + return; + } + + 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')} + +
+ +
+ {assignToMembers.length === 0 ? ( +
+ {t('noOneSelected')} +
+ ) : ( + assignToMembers.map((member) => ( +
+ {member.firstName} {member.lastName} + removeMember(member._id)} + data-testid="clearSelectedMember" + /> +
+ )) + )} +
+ +
+
+ + + setMemberToAssignToSearchFirstName(e.target.value.trim()) + } + data-testid="searchByFirstName" + autoComplete="off" + /> +
+
+ + + setMemberToAssignToSearchLastName(e.target.value.trim()) + } + data-testid="searchByLastName" + autoComplete="off" + /> +
+
+ + {userTagsMembersToAssignToLoading ? ( +
+ +
+ ) : ( + <> +
+ } + scrollableTarget="addPeopleToTagScrollableDiv" + > + row.id} + slots={{ + noRowsOverlay: /* istanbul ignore next */ () => ( + + {t('noMoreMembersFound')} + + ), + }} + sx={{ + ...dataGridStyle, + '& .MuiDataGrid-topContainer': { + position: 'static', + }, + '& .MuiDataGrid-virtualScrollerContent': { + marginTop: '0', + }, + }} + 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..fbaf812186 --- /dev/null +++ b/src/components/AddPeopleToTag/AddPeopleToTagsMocks.ts @@ -0,0 +1,292 @@ +import { ADD_PEOPLE_TO_TAG } from 'GraphQl/Mutations/TagMutations'; +import { USER_TAGS_MEMBERS_TO_ASSIGN_TO } from 'GraphQl/Queries/userTagQueries'; +import { TAGS_QUERY_DATA_CHUNK_SIZE } from 'utils/organizationTagsUtils'; + +export const MOCKS = [ + { + request: { + query: USER_TAGS_MEMBERS_TO_ASSIGN_TO, + variables: { + id: '1', + first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { + firstName: { starts_with: '' }, + lastName: { starts_with: '' }, + }, + }, + }, + result: { + data: { + getUsersToAssignTo: { + 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', + }, + { + 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: '1', + endCursor: '10', + hasNextPage: true, + hasPreviousPage: false, + }, + totalCount: 12, + }, + }, + }, + }, + }, + { + request: { + query: USER_TAGS_MEMBERS_TO_ASSIGN_TO, + variables: { + id: '1', + first: TAGS_QUERY_DATA_CHUNK_SIZE, + after: '10', + where: { + firstName: { starts_with: '' }, + lastName: { starts_with: '' }, + }, + }, + }, + result: { + data: { + getUsersToAssignTo: { + name: 'tag1', + usersToAssignTo: { + edges: [ + { + node: { + _id: '11', + firstName: 'member', + lastName: '11', + }, + cursor: '11', + }, + { + node: { + _id: '12', + firstName: 'member', + lastName: '12', + }, + cursor: '12', + }, + ], + pageInfo: { + startCursor: '11', + endCursor: '12', + hasNextPage: false, + hasPreviousPage: true, + }, + totalCount: 12, + }, + }, + }, + }, + }, + { + request: { + query: USER_TAGS_MEMBERS_TO_ASSIGN_TO, + variables: { + id: '1', + first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { + firstName: { starts_with: 'usersToAssignTo' }, + lastName: { starts_with: '' }, + }, + }, + }, + result: { + data: { + getUsersToAssignTo: { + name: 'tag1', + usersToAssignTo: { + edges: [ + { + node: { + _id: '1', + firstName: 'usersToAssignTo', + lastName: 'user1', + }, + cursor: '1', + }, + { + node: { + _id: '2', + firstName: 'usersToAssignTo', + lastName: 'user2', + }, + cursor: '2', + }, + ], + pageInfo: { + startCursor: '1', + endCursor: '2', + hasNextPage: false, + hasPreviousPage: false, + }, + totalCount: 2, + }, + }, + }, + }, + }, + { + request: { + query: USER_TAGS_MEMBERS_TO_ASSIGN_TO, + variables: { + id: '1', + first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { + firstName: { starts_with: '' }, + lastName: { starts_with: 'userToAssignTo' }, + }, + }, + }, + result: { + data: { + getUsersToAssignTo: { + name: 'tag1', + usersToAssignTo: { + edges: [ + { + node: { + _id: '1', + firstName: 'first', + lastName: 'userToAssignTo', + }, + cursor: '1', + }, + { + node: { + _id: '2', + firstName: 'second', + lastName: 'userToAssignTo', + }, + cursor: '2', + }, + ], + pageInfo: { + startCursor: '1', + endCursor: '2', + hasNextPage: false, + hasPreviousPage: false, + }, + totalCount: 2, + }, + }, + }, + }, + }, + { + 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: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { + firstName: { starts_with: '' }, + lastName: { starts_with: '' }, + }, + }, + }, + error: new Error('Mock Graphql Error'), + }, +]; diff --git a/src/components/Advertisements/Advertisements.module.css b/src/components/Advertisements/Advertisements.module.css index 8a34c03be5..6d9eb7f612 100644 --- a/src/components/Advertisements/Advertisements.module.css +++ b/src/components/Advertisements/Advertisements.module.css @@ -1,6 +1,13 @@ .container { display: flex; } +.listBox { + display: grid; + width: 100%; + grid-template-rows: auto; + grid-template-columns: repeat(6, 1fr); + grid-gap: 0.8rem 0.4rem; +} .logintitle { color: #707070; @@ -11,15 +18,24 @@ border-bottom: 3px solid #31bb6b; width: 15%; } - +.input { + display: flex; + position: relative; + width: 560px; +} +.justifysp { + display: grid; + width: 100%; + margin-top: 30px; +} .actioninput { text-decoration: none; - margin-bottom: 50px; + /* margin-bottom: 50px; */ border-color: #e8e5e5; - width: 80%; + background-color: white; border-radius: 7px; - padding-top: 5px; - padding-bottom: 5px; + padding-top: 10px; + padding-bottom: 10px; padding-right: 10px; padding-left: 10px; box-shadow: none; diff --git a/src/components/Advertisements/Advertisements.test.tsx b/src/components/Advertisements/Advertisements.spec.tsx similarity index 96% rename from src/components/Advertisements/Advertisements.test.tsx rename to src/components/Advertisements/Advertisements.spec.tsx index c0992a1012..1e2d92b392 100644 --- a/src/components/Advertisements/Advertisements.test.tsx +++ b/src/components/Advertisements/Advertisements.spec.tsx @@ -1,4 +1,6 @@ import React, { act } from 'react'; +import { describe, test, expect, vi } from 'vitest'; + import { ApolloClient, ApolloLink, @@ -7,25 +9,28 @@ import { InMemoryCache, } from '@apollo/client'; import { MockedProvider } from '@apollo/client/testing'; + import { fireEvent, render, screen } from '@testing-library/react'; -import 'jest-location-mock'; import type { DocumentNode, NormalizedCacheObject } from '@apollo/client'; import userEvent from '@testing-library/user-event'; import { BACKEND_URL } from 'Constant/constant'; -import { ADD_ADVERTISEMENT_MUTATION } from 'GraphQl/Mutations/mutations'; + +import { ADD_ADVERTISEMENT_MUTATION } from '../../GraphQl/Mutations/mutations'; import { ORGANIZATIONS_LIST, ORGANIZATION_ADVERTISEMENT_LIST, PLUGIN_GET, -} from 'GraphQl/Queries/Queries'; +} from '../../GraphQl/Queries/Queries'; + import { I18nextProvider } from 'react-i18next'; + import { Provider } from 'react-redux'; import { BrowserRouter } from 'react-router-dom'; import { ToastContainer } from 'react-toastify'; -import { store } from 'state/store'; -import i18nForTest from 'utils/i18nForTest'; -import useLocalStorage from 'utils/useLocalstorage'; +import { store } from '../../state/store'; +import i18nForTest from '../../utils/i18nForTest'; +import useLocalStorage from '../../utils/useLocalstorage'; import Advertisement from './Advertisements'; const { getItem } = useLocalStorage(); @@ -50,18 +55,22 @@ const client: ApolloClient = new ApolloClient({ link: ApolloLink.from([httpLink]), }); -jest.mock('components/AddOn/support/services/Plugin.helper', () => ({ +vi.mock('components/AddOn/support/services/Plugin.helper', () => ({ __esModule: true, - default: jest.fn().mockImplementation(() => ({ - fetchInstalled: jest.fn().mockResolvedValue([]), - fetchStore: jest.fn().mockResolvedValue([]), + default: vi.fn().mockImplementation(() => ({ + fetchInstalled: vi.fn().mockResolvedValue([]), + fetchStore: vi.fn().mockResolvedValue([]), })), })); let mockID: string | undefined = '1'; -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useParams: () => ({ orgId: mockID }), -})); + +vi.mock('react-router-dom', async () => { + const actual = await vi.importActual('react-router-dom'); + return { + ...actual, + useParams: () => ({ orgId: mockID }), + }; +}); const today = new Date(); const tomorrow = today; @@ -461,23 +470,21 @@ describe('Testing Advertisement Component', () => { await wait(); const date = await screen.findAllByTestId('Ad_end_date'); - const dateString = date[1].innerHTML; + const dateString = date[0].innerHTML; const dateMatch = dateString.match( /\b(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)\s+(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+(\d{1,2})\s+(\d{4})\b/, ); let dateObject = new Date(); - if (dateMatch) { const monthName = dateMatch[1]; const day = parseInt(dateMatch[2], 10); const year = parseInt(dateMatch[3], 10); - const monthIndex = 'JanFebMarAprMayJunJulAugSepOctNovDec'.indexOf(monthName) / 3; dateObject = new Date(year, monthIndex, day); } - + console.log(dateObject); expect(dateObject.getTime()).toBeLessThan(new Date().getTime()); }); diff --git a/src/components/Advertisements/Advertisements.tsx b/src/components/Advertisements/Advertisements.tsx index f20c2a7d8e..5f0e2b2033 100644 --- a/src/components/Advertisements/Advertisements.tsx +++ b/src/components/Advertisements/Advertisements.tsx @@ -2,30 +2,16 @@ import React, { useEffect, useState } from 'react'; import styles from './Advertisements.module.css'; import { useQuery } from '@apollo/client'; import { ORGANIZATION_ADVERTISEMENT_LIST } from 'GraphQl/Queries/Queries'; -import { Col, Row, Tab, Tabs } from 'react-bootstrap'; +import { Button, Col, Form, Row, Tab, Tabs } from 'react-bootstrap'; import { useTranslation } from 'react-i18next'; import AdvertisementEntry from './core/AdvertisementEntry/AdvertisementEntry'; import AdvertisementRegister from './core/AdvertisementRegister/AdvertisementRegister'; import { useParams } from 'react-router-dom'; import type { InterfaceQueryOrganizationAdvertisementListItem } from 'utils/interfaces'; import InfiniteScroll from 'react-infinite-scroll-component'; +import { Search } from '@mui/icons-material'; -/** - * 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 +export default function advertisements(): JSX.Element { const { orgId: currentOrgId } = useParams(); // Translation hook for internationalization const { t } = useTranslation('translation', { keyPrefix: 'advertisement' }); @@ -43,20 +29,14 @@ export default function Advertisements(): JSX.Element { 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' + endDate: string; + startDate: string; }; // GraphQL query to fetch the list of advertisements - const { - data: orgAdvertisementListData, - refetch, - }: { - data?: { - organizations: InterfaceQueryOrganizationAdvertisementListItem[]; - }; - refetch: () => void; - } = useQuery(ORGANIZATION_ADVERTISEMENT_LIST, { + const { data: orgAdvertisementListData, refetch } = useQuery<{ + organizations: InterfaceQueryOrganizationAdvertisementListItem[]; + }>(ORGANIZATION_ADVERTISEMENT_LIST, { variables: { id: currentOrgId, after: after, @@ -99,19 +79,45 @@ export default function Advertisements(): JSX.Element { return ( <> - +
- {/* Component for registering a new advertisement */} - + +
+ setSearchText("search")} + /> + +
+ + - {/* Tabs for active and archived advertisements */} - {/* Tab for active advertisements */} - + - - {/* Tab for archived advertisements */} new Date(ad.endDate) < new Date(), ).length !== 0 && (
-
{tCommon('endOfResults')}
+
{t('endOfResults')}
) } diff --git a/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.module.css b/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.module.css index 879d96a0a0..e4f244807f 100644 --- a/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.module.css +++ b/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.module.css @@ -20,7 +20,7 @@ .admedia { object-fit: cover; - height: 20rem; + height: 16rem; } .buttons { @@ -28,6 +28,10 @@ justify-content: flex-end; } +.card { + width: 28rem; +} + .dropdownButton { background-color: transparent; color: #000; diff --git a/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.test.tsx b/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.spec.tsx similarity index 90% rename from src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.test.tsx rename to src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.spec.tsx index dbd6f88cc3..4d27df6e22 100644 --- a/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.test.tsx +++ b/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.spec.tsx @@ -21,6 +21,8 @@ import useLocalStorage from 'utils/useLocalstorage'; import { MockedProvider } from '@apollo/client/testing'; import { ORGANIZATION_ADVERTISEMENT_LIST } from 'GraphQl/Queries/OrganizationQueries'; import { DELETE_ADVERTISEMENT_BY_ID } from 'GraphQl/Mutations/mutations'; +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import '@testing-library/jest-dom'; const { getItem } = useLocalStorage(); @@ -30,7 +32,6 @@ const httpLink = new HttpLink({ authorization: 'Bearer ' + getItem('token') || '', }, }); - const translations = JSON.parse( JSON.stringify( i18nForTest.getDataByLanguage('en')?.translation?.advertisement ?? null, @@ -42,22 +43,30 @@ const client: ApolloClient = new ApolloClient({ link: ApolloLink.from([httpLink]), }); -const mockUseMutation = jest.fn(); -jest.mock('@apollo/client', () => { - const originalModule = jest.requireActual('@apollo/client'); +const mockUseMutation = vi.fn(); +vi.mock('@apollo/client', async () => { + const actual = await vi.importActual('@apollo/client'); return { - ...originalModule, + ...actual, useMutation: () => mockUseMutation(), }; }); -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useParams: () => ({ orgId: '1' }), -})); + +vi.mock('react-router-dom', async () => { + const actual = await vi.importActual('react-router-dom'); + return { + ...actual, + useParams: () => ({ orgId: '1' }), + }; +}); describe('Testing Advertisement Entry Component', () => { - test('Testing rendering and deleting of advertisement', async () => { - const deleteAdByIdMock = jest.fn(); + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('Testing rendering and deleting of advertisement', async () => { + const deleteAdByIdMock = vi.fn(); mockUseMutation.mockReturnValue([deleteAdByIdMock]); const { getByTestId, getAllByText } = render( @@ -73,7 +82,7 @@ describe('Testing Advertisement Entry Component', () => { name="Advert1" organizationId="1" type="POPUP" - setAfter={jest.fn()} + setAfter={vi.fn()} /> @@ -130,13 +139,13 @@ describe('Testing Advertisement Entry Component', () => { expect(deletionFailedText).toBeNull(); }); }); + it('should use default props when none are provided', () => { render( , - ): void { + setAfter={function () // _value: React.SetStateAction, + : void { throw new Error('Function not implemented.'); }} />, @@ -156,9 +165,9 @@ describe('Testing Advertisement Entry Component', () => { // 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'; @@ -176,9 +185,8 @@ describe('Testing Advertisement Entry Component', () => { startDate={mockStartDate} organizationId={mockOrganizationId} id={''} - setAfter={function ( - _value: React.SetStateAction, - ): void { + setAfter={function () // _value: React.SetStateAction, + : void { throw new Error('Function not implemented.'); }} />, @@ -186,8 +194,13 @@ describe('Testing Advertisement Entry Component', () => { // Check that the component renders with provided values expect(getByText(mockName)).toBeInTheDocument(); - // Add more checks based on how each prop affects rendering + expect(getByText(mockType)).toBeInTheDocument(); + expect(screen.getByTestId('media')).toHaveAttribute('src', mockMediaUrl); + expect( + getByText(`Ends on ${mockEndDate.toDateString()}`), + ).toBeInTheDocument(); }); + it('should open and close the dropdown when options button is clicked', () => { const { getByTestId, queryByText, getAllByText } = render( @@ -203,7 +216,7 @@ describe('Testing Advertisement Entry Component', () => { name="Advert1" organizationId="1" type="POPUP" - setAfter={jest.fn()} + setAfter={vi.fn()} /> @@ -235,8 +248,8 @@ describe('Testing Advertisement Entry Component', () => { expect(queryByText('Edit')).toBeNull(); }); - test('Updates the advertisement and shows success toast on successful update', async () => { - const updateAdByIdMock = jest.fn().mockResolvedValue({ + it('Updates the advertisement and shows success toast on successful update', async () => { + const updateAdByIdMock = vi.fn().mockResolvedValue({ data: { updateAdvertisement: { advertisement: { @@ -266,7 +279,7 @@ describe('Testing Advertisement Entry Component', () => { organizationId="1" mediaUrl="" id="1" - setAfter={jest.fn()} + setAfter={vi.fn()} /> @@ -312,8 +325,8 @@ describe('Testing Advertisement Entry Component', () => { }); }); - test('Simulating if the mutation doesnt have data variable while updating', async () => { - const updateAdByIdMock = jest.fn().mockResolvedValue({ + it('Simulating if the mutation doesnt have data variable while updating', async () => { + const updateAdByIdMock = vi.fn().mockResolvedValue({ updateAdvertisement: { _id: '1', name: 'Updated Advertisement', @@ -336,7 +349,7 @@ describe('Testing Advertisement Entry Component', () => { organizationId="1" mediaUrl="" id="1" - setAfter={jest.fn()} + setAfter={vi.fn()} /> @@ -372,15 +385,13 @@ describe('Testing Advertisement Entry Component', () => { }); }); - test('Simulating if the mutation does not have data variable while registering', async () => { - Object.defineProperty(window, 'location', { - configurable: true, - value: { - reload: jest.fn(), - href: 'https://example.com/page/id=1', - }, + it('Simulating if the mutation does not have data variable while registering', async () => { + vi.stubGlobal('location', { + reload: vi.fn(), + href: 'https://example.com/page/id=1', }); - const createAdByIdMock = jest.fn().mockResolvedValue({ + + const createAdByIdMock = vi.fn().mockResolvedValue({ data1: { createAdvertisement: { _id: '1', @@ -397,7 +408,7 @@ describe('Testing Advertisement Entry Component', () => { { } @@ -449,8 +460,9 @@ describe('Testing Advertisement Entry Component', () => { }, }); }); - test('delet advertisement', async () => { - const deleteAdByIdMock = jest.fn(); + + it('delete advertisement', async () => { + const deleteAdByIdMock = vi.fn(); const mocks = [ { request: { @@ -576,7 +588,7 @@ describe('Testing Advertisement Entry Component', () => { name="Advert1" organizationId="1" type="POPUP" - setAfter={jest.fn()} + setAfter={vi.fn()} /> diff --git a/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.tsx b/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.tsx index 7368ded68e..7656f1f0cf 100644 --- a/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.tsx +++ b/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.tsx @@ -38,6 +38,7 @@ function AdvertisementEntry({ startDate = new Date(), setAfter, }: InterfaceAddOnEntryProps): JSX.Element { + console.log(id, type); const { t } = useTranslation('translation', { keyPrefix: 'advertisement' }); const { t: tCommon } = useTranslation('common'); @@ -98,7 +99,7 @@ function AdvertisementEntry({ {Array.from({ length: 1 }).map((_, idx) => ( - +
)} - + {formStatus === 'register' ? ( {t('addNew')} ) : ( @@ -405,6 +405,7 @@ function advertisementRegister({ diff --git a/src/components/AgendaCategory/AgendaCategoryContainer.test.tsx b/src/components/AgendaCategory/AgendaCategoryContainer.spec.tsx similarity index 97% rename from src/components/AgendaCategory/AgendaCategoryContainer.test.tsx rename to src/components/AgendaCategory/AgendaCategoryContainer.spec.tsx index 5ddab82aec..74880558b4 100644 --- a/src/components/AgendaCategory/AgendaCategoryContainer.test.tsx +++ b/src/components/AgendaCategory/AgendaCategoryContainer.spec.tsx @@ -8,9 +8,7 @@ import { fireEvent, } 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'; @@ -25,14 +23,15 @@ import { StaticMockLink } from 'utils/StaticMockLink'; import AgendaCategoryContainer from './AgendaCategoryContainer'; import { props, props2 } from './AgendaCategoryContainerProps'; import { MOCKS, MOCKS_ERROR_MUTATIONS } from './AgendaCategoryContainerMocks'; +import { vi, describe, test, expect } from 'vitest'; const link = new StaticMockLink(MOCKS, true); const link2 = new StaticMockLink(MOCKS_ERROR_MUTATIONS, true); -jest.mock('react-toastify', () => ({ +vi.mock('react-toastify', () => ({ toast: { - success: jest.fn(), - error: jest.fn(), + success: vi.fn(), + error: vi.fn(), }, })); @@ -269,7 +268,9 @@ describe('Testing Agenda Category Component', () => { userEvent.click(screen.getByTestId('editAgendaCategoryBtn')); await waitFor(() => { - expect(toast.success).toBeCalledWith(translations.agendaCategoryUpdated); + expect(toast.success).toHaveBeenCalledWith( + translations.agendaCategoryUpdated, + ); }); }); @@ -362,7 +363,9 @@ describe('Testing Agenda Category Component', () => { userEvent.click(screen.getByTestId('deleteAgendaCategoryBtn')); await waitFor(() => { - expect(toast.success).toBeCalledWith(translations.agendaCategoryDeleted); + expect(toast.success).toHaveBeenCalledWith( + translations.agendaCategoryDeleted, + ); }); }); diff --git a/src/components/AgendaCategory/AgendaCategoryContainerProps.ts b/src/components/AgendaCategory/AgendaCategoryContainerProps.ts index 5181eec153..3d8128128c 100644 --- a/src/components/AgendaCategory/AgendaCategoryContainerProps.ts +++ b/src/components/AgendaCategory/AgendaCategoryContainerProps.ts @@ -1,4 +1,5 @@ type AgendaCategoryConnectionType = 'Organization'; +import { vi } from 'vitest'; export const props = { agendaCategoryConnection: 'Organization' as AgendaCategoryConnectionType, @@ -24,11 +25,11 @@ export const props = { }, }, ], - agendaCategoryRefetch: jest.fn(), + agendaCategoryRefetch: vi.fn(), }; export const props2 = { agendaCategoryConnection: 'Organization' as AgendaCategoryConnectionType, agendaCategoryData: [], - agendaCategoryRefetch: jest.fn(), + agendaCategoryRefetch: vi.fn(), }; diff --git a/src/components/AgendaItems/AgendaItemsContainer.test.tsx b/src/components/AgendaItems/AgendaItemsContainer.spec.tsx similarity index 97% rename from src/components/AgendaItems/AgendaItemsContainer.test.tsx rename to src/components/AgendaItems/AgendaItemsContainer.spec.tsx index 7ceb8b4d08..f8f6ab948d 100644 --- a/src/components/AgendaItems/AgendaItemsContainer.test.tsx +++ b/src/components/AgendaItems/AgendaItemsContainer.spec.tsx @@ -7,9 +7,7 @@ import { fireEvent, } 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'; @@ -24,20 +22,20 @@ import { StaticMockLink } from 'utils/StaticMockLink'; import { props, props2 } from './AgendaItemsContainerProps'; import { MOCKS, MOCKS_ERROR } from './AgendaItemsContainerMocks'; import AgendaItemsContainer from './AgendaItemsContainer'; - +import { describe, test, expect, vi } from 'vitest'; const link = new StaticMockLink(MOCKS, true); const link2 = new StaticMockLink(MOCKS_ERROR, true); -jest.mock('react-toastify', () => ({ +vi.mock('react-toastify', () => ({ toast: { - success: jest.fn(), - error: jest.fn(), + success: vi.fn(), + error: vi.fn(), }, })); //temporarily fixes react-beautiful-dnd droppable method's depreciation error //needs to be fixed in React 19 -jest.spyOn(console, 'error').mockImplementation((message) => { +vi.spyOn(console, 'error').mockImplementation((message) => { if (message.includes('Support for defaultProps will be removed')) { return; } @@ -371,7 +369,9 @@ describe('Testing Agenda Items components', () => { userEvent.click(screen.getByTestId('deleteAgendaItemBtn')); await waitFor(() => { - expect(toast.success).toBeCalledWith(translations.agendaItemDeleted); + expect(toast.success).toHaveBeenCalledWith( + translations.agendaItemDeleted, + ); }); }); diff --git a/src/components/AgendaItems/AgendaItemsContainerProps.ts b/src/components/AgendaItems/AgendaItemsContainerProps.ts index d6dcf3feca..f19d5ff9df 100644 --- a/src/components/AgendaItems/AgendaItemsContainerProps.ts +++ b/src/components/AgendaItems/AgendaItemsContainerProps.ts @@ -1,4 +1,5 @@ type AgendaItemConnectionType = 'Event'; +import { vi } from 'vitest'; export const props = { agendaItemConnection: 'Event' as AgendaItemConnectionType, @@ -68,7 +69,7 @@ export const props = { }, }, ], - agendaItemRefetch: jest.fn(), + agendaItemRefetch: vi.fn(), agendaItemCategories: [ { _id: 'agendaCategory1', @@ -96,6 +97,6 @@ export const props = { export const props2 = { agendaItemConnection: 'Event' as AgendaItemConnectionType, agendaItemData: [], - agendaItemRefetch: jest.fn(), + agendaItemRefetch: vi.fn(), agendaItemCategories: [], }; diff --git a/src/components/AgendaItems/AgendaItemsCreateModal.test.tsx b/src/components/AgendaItems/AgendaItemsCreateModal.spec.tsx similarity index 96% rename from src/components/AgendaItems/AgendaItemsCreateModal.test.tsx rename to src/components/AgendaItems/AgendaItemsCreateModal.spec.tsx index 5b7339ad67..35ea8c7681 100644 --- a/src/components/AgendaItems/AgendaItemsCreateModal.test.tsx +++ b/src/components/AgendaItems/AgendaItemsCreateModal.spec.tsx @@ -19,6 +19,8 @@ import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import AgendaItemsCreateModal from './AgendaItemsCreateModal'; import { toast } from 'react-toastify'; import convertToBase64 from 'utils/convertToBase64'; +import type { MockedFunction } from 'vitest'; +import { describe, test, expect, vi } from 'vitest'; const mockFormState = { title: 'Test Title', @@ -28,9 +30,9 @@ const mockFormState = { urls: ['https://example.com'], agendaItemCategoryIds: ['category'], }; -const mockHideCreateModal = jest.fn(); -const mockSetFormState = jest.fn(); -const mockCreateAgendaItemHandler = jest.fn(); +const mockHideCreateModal = vi.fn(); +const mockSetFormState = vi.fn(); +const mockCreateAgendaItemHandler = vi.fn(); const mockT = (key: string): string => key; const mockAgendaItemCategories = [ { @@ -64,14 +66,14 @@ const mockAgendaItemCategories = [ }, }, ]; -jest.mock('react-toastify', () => ({ +vi.mock('react-toastify', () => ({ toast: { - success: jest.fn(), - error: jest.fn(), + success: vi.fn(), + error: vi.fn(), }, })); -jest.mock('utils/convertToBase64'); -const mockedConvertToBase64 = convertToBase64 as jest.MockedFunction< +vi.mock('utils/convertToBase64'); +const mockedConvertToBase64 = convertToBase64 as MockedFunction< typeof convertToBase64 >; diff --git a/src/components/AgendaItems/AgendaItemsPreviewModal.test.tsx b/src/components/AgendaItems/AgendaItemsPreviewModal.spec.tsx similarity index 94% rename from src/components/AgendaItems/AgendaItemsPreviewModal.test.tsx rename to src/components/AgendaItems/AgendaItemsPreviewModal.spec.tsx index 0a7b4646ba..35c67576cc 100644 --- a/src/components/AgendaItems/AgendaItemsPreviewModal.test.tsx +++ b/src/components/AgendaItems/AgendaItemsPreviewModal.spec.tsx @@ -11,6 +11,7 @@ import { LocalizationProvider } from '@mui/x-date-pickers'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import AgendaItemsPreviewModal from './AgendaItemsPreviewModal'; +import { describe, test, expect, vi } from 'vitest'; const mockFormState = { title: 'Test Title', @@ -44,10 +45,10 @@ describe('AgendaItemsPreviewModal', () => { diff --git a/src/components/AgendaItems/AgendaItemsUpdateModal.test.tsx b/src/components/AgendaItems/AgendaItemsUpdateModal.spec.tsx similarity index 96% rename from src/components/AgendaItems/AgendaItemsUpdateModal.test.tsx rename to src/components/AgendaItems/AgendaItemsUpdateModal.spec.tsx index 0f11ea31b2..8d277419fa 100644 --- a/src/components/AgendaItems/AgendaItemsUpdateModal.test.tsx +++ b/src/components/AgendaItems/AgendaItemsUpdateModal.spec.tsx @@ -12,13 +12,14 @@ 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'; +import type { MockedFunction } from 'vitest'; +import { describe, test, expect, vi } from 'vitest'; const mockFormState = { title: 'Test Title', @@ -67,19 +68,19 @@ const mockAgendaItemCategories = [ }, ]; -const mockHideUpdateModal = jest.fn(); -const mockSetFormState = jest.fn(); -const mockUpdateAgendaItemHandler = jest.fn(); +const mockHideUpdateModal = vi.fn(); +const mockSetFormState = vi.fn(); +const mockUpdateAgendaItemHandler = vi.fn(); const mockT = (key: string): string => key; -jest.mock('react-toastify', () => ({ +vi.mock('react-toastify', () => ({ toast: { - success: jest.fn(), - error: jest.fn(), + success: vi.fn(), + error: vi.fn(), }, })); -jest.mock('utils/convertToBase64'); -const mockedConvertToBase64 = convertToBase64 as jest.MockedFunction< +vi.mock('utils/convertToBase64'); +const mockedConvertToBase64 = convertToBase64 as MockedFunction< typeof convertToBase64 >; diff --git a/src/components/Avatar/Avatar.spec.tsx b/src/components/Avatar/Avatar.spec.tsx new file mode 100644 index 0000000000..2721595304 --- /dev/null +++ b/src/components/Avatar/Avatar.spec.tsx @@ -0,0 +1,92 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import '@testing-library/jest-dom'; +import { describe, test, expect, vi } from 'vitest'; +import Avatar from './Avatar'; + +/** + * Unit tests for the `Avatar` component. + * + * The tests ensure the `Avatar` component renders correctly with various props. + * Mocked dependencies are used to isolate the component and verify its behavior. + * + */ + +vi.mock('state/store', () => ({ + store: { + getState: vi.fn(() => ({ + auth: { + user: null, + loading: false, + }, + })), + subscribe: vi.fn(), + dispatch: vi.fn(), + }, +})); + +vi.mock('utils/i18nForTest', () => ({ + __esModule: true, + default: vi.fn(() => ({ + t: (key: string) => key, + })), +})); + +describe('Avatar component', () => { + /** + * Test: Verifies the `Avatar` component renders correctly with the `name` and `alt` attributes. + * + * Steps: + * 1. Render the `Avatar` component with `name`, `alt`, and `size` props. + * 2. Check if the avatar image is present in the document. + * 3. Validate the `src` attribute is defined. + */ + test('renders with name and alt attribute', () => { + const testName = 'John Doe'; + const testAlt = 'Test Alt Text'; + const testSize = 64; + + const { getByAltText } = render( + , + ); + + const avatarElement = getByAltText(testAlt); + + expect(avatarElement).toBeInTheDocument(); + expect(avatarElement.getAttribute('src')).toBeDefined(); + }); + + /** + * Test: Verifies the `Avatar` component renders correctly with custom style and `data-testid`. + * + * Steps: + * 1. Render the `Avatar` component with `avatarStyle` and `dataTestId` props. + * 2. Check if the avatar image is present in the document. + * 3. Validate the `className` contains the custom style. + * 4. Validate the `data-testid` attribute matches the expected value. + */ + + test('renders with custom style and data-testid', () => { + const testName = 'Jane Doe'; + const testStyle = 'custom-avatar-style'; + const testDataTestId = 'custom-avatar-test-id'; + + const { getByAltText } = render( + , + ); + + const avatarElement = getByAltText('Dummy Avatar'); + + expect(avatarElement).toBeInTheDocument(); + expect(avatarElement.getAttribute('src')).toBeDefined(); + + expect(avatarElement.className).toContain(testStyle); + + expect(avatarElement.getAttribute('data-testid')).toBe(testDataTestId); + }); +}); diff --git a/src/components/Avatar/Avatar.test.tsx b/src/components/Avatar/Avatar.test.tsx deleted file mode 100644 index d178c48a4a..0000000000 --- a/src/components/Avatar/Avatar.test.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import React from 'react'; -import { render } from '@testing-library/react'; -import Avatar from './Avatar'; -import { BrowserRouter } from 'react-router-dom'; -import { I18nextProvider } from 'react-i18next'; -import i18nForTest from 'utils/i18nForTest'; - -describe('Avatar component', () => { - test('renders with name and alt attribute', () => { - const testName = 'John Doe'; - const testAlt = 'Test Alt Text'; - const testSize = 64; - - const { getByAltText } = render( - - - - - , - ); - const avatarElement = getByAltText(testAlt); - - expect(avatarElement).toBeInTheDocument(); - expect(avatarElement.getAttribute('src')).toBeDefined(); - }); - - test('renders with custom style and data-testid', () => { - const testName = 'Jane Doe'; - const testStyle = 'custom-avatar-style'; - const testDataTestId = 'custom-avatar-test-id'; - - const { getByAltText } = render( - - - - - , - ); - const avatarElement = getByAltText('Dummy Avatar'); - - expect(avatarElement).toBeInTheDocument(); - expect(avatarElement.getAttribute('src')).toBeDefined(); - expect(avatarElement.getAttribute('class')).toContain(testStyle); - expect(avatarElement.getAttribute('data-testid')).toBe(testDataTestId); - }); -}); diff --git a/src/components/Avatar/Avatar.tsx b/src/components/Avatar/Avatar.tsx index 431c4a875a..3e2f818e3f 100644 --- a/src/components/Avatar/Avatar.tsx +++ b/src/components/Avatar/Avatar.tsx @@ -41,7 +41,7 @@ const Avatar = ({ size: size || 128, seed: name, radius: radius || 0, - }).toDataUriSync(); + }).toDataUri(); }, [name, size]); const svg = avatar?.toString(); diff --git a/src/components/ChangeLanguageDropdown/ChangeLanguageDropdown.test.tsx b/src/components/ChangeLanguageDropdown/ChangeLanguageDropdown.spec.tsx similarity index 93% rename from src/components/ChangeLanguageDropdown/ChangeLanguageDropdown.test.tsx rename to src/components/ChangeLanguageDropdown/ChangeLanguageDropdown.spec.tsx index dc14f6ce17..cbaa628339 100644 --- a/src/components/ChangeLanguageDropdown/ChangeLanguageDropdown.test.tsx +++ b/src/components/ChangeLanguageDropdown/ChangeLanguageDropdown.spec.tsx @@ -11,6 +11,7 @@ import { MockedProvider } from '@apollo/react-testing'; import { UPDATE_USER_MUTATION } from 'GraphQl/Mutations/mutations'; import { StaticMockLink } from 'utils/StaticMockLink'; import useLocalStorage from 'utils/useLocalstorage'; +import { describe, expect, it } from 'vitest'; // import { Provider } from 'react-redux'; // import { store } from 'state/store'; const { setItem } = useLocalStorage(); @@ -52,7 +53,7 @@ const MOCKS = [ const link = new StaticMockLink(MOCKS, true); describe('Testing Change Language Dropdown', () => { - test('Component Should be rendered properly', async () => { + it('Component Should be rendered properly', async () => { const { getByTestId } = render( @@ -81,7 +82,7 @@ describe('Testing Change Language Dropdown', () => { }); }); - test('Component Should accept props properly', async () => { + it('Component Should accept props properly', async () => { const props = { parentContainerStyle: 'parentContainerStyle', btnStyle: 'btnStyle', @@ -103,7 +104,7 @@ describe('Testing Change Language Dropdown', () => { getByTestId('dropdown-btn-0').className.includes(props.btnTextStyle); }); - test('Testing when language cookie is not set', async () => { + it('Testing when language cookie is not set', async () => { Object.defineProperty(window.document, 'cookie', { writable: true, value: 'i18next=', @@ -121,7 +122,7 @@ describe('Testing Change Language Dropdown', () => { expect(cookies.get('i18next')).toBe(''); }); - test('Testing change language functionality', async () => { + it('Testing change language functionality', async () => { Object.defineProperty(window.document, 'cookie', { writable: true, value: 'i18next=sp', diff --git a/src/components/CheckIn/CheckInModal.test.tsx b/src/components/CheckIn/CheckInModal.spec.tsx similarity index 89% rename from src/components/CheckIn/CheckInModal.test.tsx rename to src/components/CheckIn/CheckInModal.spec.tsx index 1660c7c4bb..4f5a05328e 100644 --- a/src/components/CheckIn/CheckInModal.test.tsx +++ b/src/components/CheckIn/CheckInModal.spec.tsx @@ -12,6 +12,7 @@ import { LocalizationProvider } from '@mui/x-date-pickers'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { checkInQueryMock } from './mocks'; import { StaticMockLink } from 'utils/StaticMockLink'; +import { vi } from 'vitest'; const link = new StaticMockLink(checkInQueryMock, true); @@ -19,9 +20,14 @@ describe('Testing Check In Attendees Modal', () => { const props = { show: true, eventId: 'event123', - handleClose: jest.fn(), + handleClose: vi.fn(), }; + /** + * Test case for rendering the CheckInModal component and verifying functionality. + * It checks that the modal renders fetched users and verifies the filtering mechanism. + */ + test('The modal should be rendered, and all the fetched users should be shown properly and user filtering should work', async () => { const { queryByText, queryByLabelText } = render( diff --git a/src/components/CheckIn/CheckInWrapper.module.css b/src/components/CheckIn/CheckInWrapper.module.css deleted file mode 100644 index f5f42546c3..0000000000 --- a/src/components/CheckIn/CheckInWrapper.module.css +++ /dev/null @@ -1,13 +0,0 @@ -button .iconWrapper { - width: 32px; - padding-right: 4px; - margin-right: 4px; - transform: translateY(4px); -} - -button .iconWrapperSm { - width: 32px; - display: flex; - justify-content: center; - align-items: center; -} diff --git a/src/components/CheckIn/CheckInWrapper.test.tsx b/src/components/CheckIn/CheckInWrapper.spec.tsx similarity index 76% rename from src/components/CheckIn/CheckInWrapper.test.tsx rename to src/components/CheckIn/CheckInWrapper.spec.tsx index 81f53d0043..06b2695f88 100644 --- a/src/components/CheckIn/CheckInWrapper.test.tsx +++ b/src/components/CheckIn/CheckInWrapper.spec.tsx @@ -13,6 +13,19 @@ import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { checkInQueryMock } from './mocks'; import { StaticMockLink } from 'utils/StaticMockLink'; +/** + * This file contains unit tests for the CheckInWrapper component. + * + * The tests cover: + * - Rendering and behavior of the modal component. + * - Functionality of the button to open and close the modal. + * - Integration with mocked GraphQL queries for testing Apollo Client. + * + * Purpose: + * These tests ensure that the CheckInWrapper component behaves as expected + * when opening and closing modals, and correctly integrates with its dependencies. + */ + const link = new StaticMockLink(checkInQueryMock, true); describe('Testing CheckIn Wrapper', () => { @@ -20,7 +33,7 @@ describe('Testing CheckIn Wrapper', () => { eventId: 'event123', }; - test('The button to open and close the modal should work properly', async () => { + it('The button to open and close the modal should work properly', async () => { render( diff --git a/src/components/CheckIn/CheckInWrapper.tsx b/src/components/CheckIn/CheckInWrapper.tsx index 859ae1f869..7b35ce1483 100644 --- a/src/components/CheckIn/CheckInWrapper.tsx +++ b/src/components/CheckIn/CheckInWrapper.tsx @@ -1,8 +1,7 @@ import React, { useState } from 'react'; import { CheckInModal } from './CheckInModal'; import { Button } from 'react-bootstrap'; -import IconComponent from 'components/IconComponent/IconComponent'; -import styles from './CheckInWrapper.module.css'; +import style from '../../style/app.module.css'; type PropType = { eventId: string; @@ -21,19 +20,19 @@ export const CheckInWrapper = ({ eventId }: PropType): JSX.Element => { return ( <> {showModal && ( diff --git a/src/components/CheckIn/TableRow.test.tsx b/src/components/CheckIn/TableRow.spec.tsx similarity index 71% rename from src/components/CheckIn/TableRow.test.tsx rename to src/components/CheckIn/TableRow.spec.tsx index 14c3d20c29..4e11302fe7 100644 --- a/src/components/CheckIn/TableRow.test.tsx +++ b/src/components/CheckIn/TableRow.spec.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { fireEvent, render, waitFor } from '@testing-library/react'; +import { fireEvent, render } from '@testing-library/react'; import { TableRow } from './TableRow'; import { BrowserRouter } from 'react-router-dom'; import { Provider } from 'react-redux'; @@ -11,10 +11,15 @@ import { LocalizationProvider } from '@mui/x-date-pickers'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { MockedProvider } from '@apollo/react-testing'; import { checkInMutationSuccess, checkInMutationUnsuccess } from './mocks'; +import { vi } from 'vitest'; + +/** + * Test suite for the `TableRow` component, focusing on the CheckIn table functionality. + */ describe('Testing Table Row for CheckIn Table', () => { beforeEach(() => { - jest.clearAllMocks(); + vi.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 () => { @@ -26,7 +31,7 @@ describe('Testing Table Row for CheckIn Table', () => { checkIn: null, eventId: `event123`, }, - refetch: jest.fn(), + refetch: vi.fn(), }; const { findByText } = render( @@ -63,7 +68,7 @@ describe('Testing Table Row for CheckIn Table', () => { }, eventId: 'event123', }, - refetch: jest.fn(), + refetch: vi.fn(), }; const { findByText } = render( @@ -81,8 +86,8 @@ describe('Testing Table Row for CheckIn Table', () => { , ); - global.URL.createObjectURL = jest.fn(() => 'mockURL'); - global.window.open = jest.fn(); + global.URL.createObjectURL = vi.fn(() => 'mockURL'); + global.window.open = vi.fn(); expect(await findByText('Checked In')).toBeInTheDocument(); expect(await findByText('Download Tag')).toBeInTheDocument(); @@ -93,7 +98,7 @@ describe('Testing Table Row for CheckIn Table', () => { expect(await findByText('PDF generated successfully!')).toBeInTheDocument(); // Cleanup mocks - jest.clearAllMocks(); + vi.clearAllMocks(); }); test('Upon failing of check in mutation, the appropriate error message should be shown', async () => { @@ -105,7 +110,7 @@ describe('Testing Table Row for CheckIn Table', () => { checkIn: null, eventId: `event123`, }, - refetch: jest.fn(), + refetch: vi.fn(), }; const { findByText } = render( @@ -130,4 +135,45 @@ describe('Testing Table Row for CheckIn Table', () => { expect(await findByText('Error checking in')).toBeInTheDocument(); expect(await findByText('Oops')).toBeInTheDocument(); }); + + test('If PDF generation fails, the error message should be shown', async () => { + const props = { + data: { + id: `123`, + name: '', + userId: `user123`, + checkIn: { + _id: '123', + time: '12:00:00', + }, + eventId: `event123`, + }, + refetch: vi.fn(), + }; + + const { findByText } = render( + + + + + + + + + + + + , + ); + + // Mocking the PDF generation function to throw an error + global.URL.createObjectURL = vi.fn(() => 'mockURL'); + global.window.open = vi.fn(); + + fireEvent.click(await findByText('Download Tag')); + + expect( + await findByText('Error generating pdf: Invalid or empty name provided'), + ).toBeInTheDocument(); + }); }); diff --git a/src/components/CheckIn/TableRow.tsx b/src/components/CheckIn/TableRow.tsx index 38d1dda912..b2bd6e11cb 100644 --- a/src/components/CheckIn/TableRow.tsx +++ b/src/components/CheckIn/TableRow.tsx @@ -66,7 +66,11 @@ export const TableRow = ({ */ const generateTag = async (): Promise => { try { - const inputs = [{ name: data.name }]; + const inputs = []; + if (typeof data.name !== 'string' || !data.name.trim()) { + throw new Error('Invalid or empty name provided'); + } + inputs.push({ name: data.name.trim() }); const pdf = await generate({ template: tagTemplate, inputs }); // istanbul ignore next const blob = new Blob([pdf.buffer], { type: 'application/pdf' }); diff --git a/src/components/CheckIn/tagTemplate.ts b/src/components/CheckIn/tagTemplate.ts index 4aa4475e02..611dff7b83 100644 --- a/src/components/CheckIn/tagTemplate.ts +++ b/src/components/CheckIn/tagTemplate.ts @@ -1,22 +1,16 @@ import { Template } from '@pdfme/common'; +import styles from '../../style/app.module.css'; export const tagTemplate: Template = { schemas: [ - { - name: { + [ + { + name: 'name', type: 'text', - position: { x: 14.91, y: 27.03 }, - width: 58.55, - height: 5.67, - alignment: 'center', - fontSize: 16, - characterSpacing: 0, - lineHeight: 1, - fontName: 'Roboto', - fontColor: '#08780b', - }, - }, - ], + className: `${styles['tag-template-name']}`, + } , + ], + ] as any, basePdf: 'data:application/pdf;base64,JVBERi0xLjQKJfbk/N8KMSAwIG9iago8PAovVHlwZSAvQ2F0YWxvZwovVmVyc2lvbiAvMS40Ci9QYWdlcyAyIDAgUgovU3RydWN0VHJlZVJvb3QgMyAwIFIKL01hcmtJbmZvIDQgMCBSCi9MYW5nIChlbikKL1ZpZXdlclByZWZlcmVuY2VzIDUgMCBSCj4+CmVuZG9iago2IDAgb2JqCjw8Ci9DcmVhdG9yIChDYW52YSkKL1Byb2R1Y2VyIChDYW52YSkKL0NyZWF0aW9uRGF0ZSAoRDoyMDIzMDYyMDA3MjgxMyswMCcwMCcpCi9Nb2REYXRlIChEOjIwMjMwNjIwMDcyODEzKzAwJzAwJykKL0tleXdvcmRzIChEQUZjMjhYSXViTSxCQUUycS01WEdhaykKL0F1dGhvciAoRXNoYWFuIEFnZ2Fyd2FsKQovVGl0bGUgKEJsYW5rIE5hbWUgVGFnIGluIEVtZXJhbGQgTWludCBHcmVlbiBBc3BpcmF0aW9uYWwgRWxlZ2FuY2UgU3R5bGUpCj4+CmVuZG9iagoyIDAgb2JqCjw8Ci9UeXBlIC9QYWdlcwovS2lkcyBbNyAwIFJdCi9Db3VudCAxCj4+CmVuZG9iagozIDAgb2JqCjw8Ci9UeXBlIC9TdHJ1Y3RUcmVlUm9vdAovUGFyZW50VHJlZSA4IDAgUgovUGFyZW50VHJlZU5leHRLZXkgMQovSyBbOSAwIFJdCi9JRFRyZWUgMTAgMCBSCj4+CmVuZG9iago0IDAgb2JqCjw8Ci9NYXJrZWQgdHJ1ZQovU3VzcGVjdHMgZmFsc2UKPj4KZW5kb2JqCjUgMCBvYmoKPDwKL0Rpc3BsYXlEb2NUaXRsZSB0cnVlCj4+CmVuZG9iago3IDAgb2JqCjw8Ci9UeXBlIC9QYWdlCi9SZXNvdXJjZXMgMTEgMCBSCi9NZWRpYUJveCBbMC4wIDcuOTIwMDAyNSAyNTIuMCAxNTEuOTJdCi9Db250ZW50cyAxMiAwIFIKL1N0cnVjdFBhcmVudHMgMAovUGFyZW50IDIgMCBSCi9UYWJzIC9TCi9CbGVlZEJveCBbMC4wIDcuOTIwMDAyNSAyNTIuMCAxNTEuOTJdCi9UcmltQm94IFswLjAgNy45MjAwMDI1IDI1Mi4wIDE1MS45Ml0KL0Nyb3BCb3ggWzAuMCA3LjkyMDAwMjUgMjUyLjAgMTUxLjkyXQovUm90YXRlIDAKL0Fubm90cyBbXQo+PgplbmRvYmoKOCAwIG9iago8PAovTGltaXRzIFswIDBdCi9OdW1zIFswIFsxMyAwIFIgMTQgMCBSIDE1IDAgUiAxNiAwIFIgMTcgMCBSIDE4IDAgUiAxOSAwIFJdCl0KPj4KZW5kb2JqCjkgMCBvYmoKPDwKL1R5cGUgL1N0cnVjdEVsZW0KL1MgL0RvY3VtZW50Ci9MYW5nIChlbikKL1AgMyAwIFIKL0sgWzIwIDAgUl0KL0lEIChub2RlMDAwMDE3MzgpCj4+CmVuZG9iagoxMCAwIG9iago8PAovTmFtZXMgWyhub2RlMDAwMDE3MzgpIDkgMCBSIChub2RlMDAwMDE3MzkpIDEzIDAgUiAobm9kZTAwMDAxNzQwKSAyMCAwIFIgKG5vZGUwMDAwMTc0MSkgMjEgMCBSIChub2RlMDAwMDE3NDIpIDIyIDAgUgoobm9kZTAwMDAxNzQzKSAyMyAwIFIgKG5vZGUwMDAwMTc0NCkgMjQgMCBSIChub2RlMDAwMDE3NDUpIDI1IDAgUiAobm9kZTAwMDAxNzQ2KSAyNiAwIFIgKG5vZGUwMDAwMTc0NykgMjcgMCBSCihub2RlMDAwMDE3NjEpIDI4IDAgUiAobm9kZTAwMDAxNzYyKSAyOSAwIFIgKG5vZGUwMDAwMTc2MykgMzAgMCBSIChub2RlMDAwMDE3NjQpIDMxIDAgUiAobm9kZTAwMDAxNzY1KSAzMiAwIFIKKG5vZGUwMDAwMTc2NikgMzMgMCBSIChub2RlMDAwMDE3NjcpIDE0IDAgUiAobm9kZTAwMDAxNzY4KSAzNCAwIFIgKG5vZGUwMDAwMTc2OSkgMzUgMCBSIChub2RlMDAwMDE3NzApIDM2IDAgUgoobm9kZTAwMDAxNzcxKSAxNSAwIFIgKG5vZGUwMDAwMTc3MikgMzcgMCBSIChub2RlMDAwMDE3NzMpIDM4IDAgUiAobm9kZTAwMDAxNzc0KSAzOSAwIFIgKG5vZGUwMDAwMTc3NSkgMTYgMCBSCihub2RlMDAwMDE3NzYpIDE3IDAgUiAobm9kZTAwMDAxNzc3KSA0MCAwIFIgKG5vZGUwMDAwMTc3OCkgMTggMCBSIChub2RlMDAwMDE3NzkpIDQxIDAgUiAobm9kZTAwMDAxNzgwKSA0MiAwIFIKKG5vZGUwMDAwMTc4MSkgNDMgMCBSIChub2RlMDAwMDE3ODIpIDQ0IDAgUiAobm9kZTAwMDAxNzgzKSAxOSAwIFJdCj4+CmVuZG9iagoxMSAwIG9iago8PAovUHJvY1NldCBbL1BERiAvVGV4dCAvSW1hZ2VCIC9JbWFnZUMgL0ltYWdlSV0KL0V4dEdTdGF0ZSA0NSAwIFIKL1hPYmplY3QgPDwKL1g1IDQ2IDAgUgo+PgovRm9udCA0NyAwIFIKPj4KZW5kb2JqCjEyIDAgb2JqCjw8Ci9MZW5ndGggOTc4Ci9GaWx0ZXIgL0ZsYXRlRGVjb2RlCj4+CnN0cmVhbQ0KeJytVk2PGzcMvc+v0LlAtCQl6gNYLODYmyCHAE1roL27SYDC2yDJ/wfyJM2MNFnvJpuuDdsyKZGPj0/SWHG5vgzh/cIOf1nZZsY4mdPd9HkqE5iUTHBsRc2X99Nfv5n/4HGW8b/4+whL2JT3H69NG3z5OF29dubj1xrJuWCEpET5ML3De0xA9AzROf+P6JY4B2N9/ZYMoMh03/iErJ005L0H5gEbO7HBc0AqCWw5M5uYyboCVbK2wTI5kI0hbCbfTSk7m1KKrhvPU6ZsvXDI3ZhFUJ8r86KzMTlKoy1l5ApsTlM3qkRMVEklYrd6h6nJmZ5EVSElwsSOpttOI/JuPk/sFYJ0muNgHihZM422FdNpw96C/7yxrpUOqVZGLvF5qkx/nsSmRS3z8FKripBS0YnNkj2+CZupCOmecSskSVyk8JPyjQTcg4RZyYpn55zxDmx4CqFpmlyGcMWpsaySm6a/N1YovkGxCgXhTLDJowPl73n683mkHXywpI68AfUM3OyxgbwNKaKEPIYM0VuOaTP1bsoo04vqaIUOA4SiScNgzTFZVcJMBR3klcJggwbEReWimG4VipbR2FBiditUHtnD2vOAOesoFNuKqNtOA/puPU9BE+SiRS2rtVPS8wy2FdFpIK+jPw/WXmfP0/m4xOfDwr7UqF8VNgNnSKOug2JjlkXYbFReUAGF0nwGw2F7zzRHvamkjqksXCIItn7KSSq8OenV7+b6+urt/s0Bi25uXh7209Xfag6fptu3+6fdDJtzA4LwPuhTt1XF9PI4wuIF1quInWtzyvXKPX7ADVcrLUcB2UDZlY0h5ng3XYOm/Y05/jsxFJdy9KFMPv5jrnEGH6oHLU7OMyQwO8SHxaGCDSarI3J1iM05Ek6TxUHK84oEghmofrjitiWP6AhWxNXB2hyF9dtjpf0ev9BZUhSD01jYeoer1P2S0rYEy0gwLgxpDzgjwUWYM6+H2HgVHKEx8VoylFsdCoyRUpBema8OZ5VY3Eo3025eoLh4ci21OUJzBBu4PF7p9xyhpxEezT9OvvT0EVodo33kcQV4bDEBxPgMqnUjqbIh03tLsV2JNJMKMnjn24cTCn2FX27jubS5gm0W/3CWFMuzRb0r5iwQ5SrMi9H04WiitkGWdX9p6WwRdIVaglf4YdfGeljgV3u17XfVz7v9pcawxbNJTOKkZh3+as4Ww1ILqsJRS/roE+62rPBIK5Kdj42lE3zbIBb45QOotRvu0Mrb9/Jq6fDVXzd3aym7rFnKTocWcz93N9NMzUwb5RJ3S8e76RuIroTkDQplbmRzdHJlYW0KZW5kb2JqCjEzIDAgb2JqCjw8Ci9UeXBlIC9TdHJ1Y3RFbGVtCi9TIC9GaWd1cmUKL1AgMzAgMCBSCi9LIFs0OCAwIFJdCi9JRCAobm9kZTAwMDAxNzM5KQo+PgplbmRvYmoKMTQgMCBvYmoKPDwKL1R5cGUgL1N0cnVjdEVsZW0KL1MgL05vblN0cnVjdAovUCAzMyAwIFIKL0sgWzQ5IDAgUl0KL0lEIChub2RlMDAwMDE3NjcpCj4+CmVuZG9iagoxNSAwIG9iago8PAovVHlwZSAvU3RydWN0RWxlbQovUyAvTm9uU3RydWN0Ci9QIDM2IDAgUgovSyBbNTAgMCBSXQovSUQgKG5vZGUwMDAwMTc3MSkKPj4KZW5kb2JqCjE2IDAgb2JqCjw8Ci9UeXBlIC9TdHJ1Y3RFbGVtCi9TIC9Ob25TdHJ1Y3QKL1AgMzkgMCBSCi9LIFs1MSAwIFJdCi9JRCAobm9kZTAwMDAxNzc1KQo+PgplbmRvYmoKMTcgMCBvYmoKPDwKL1R5cGUgL1N0cnVjdEVsZW0KL1MgL05vblN0cnVjdAovUCAzOSAwIFIKL0sgWzUyIDAgUl0KL0lEIChub2RlMDAwMDE3NzYpCj4+CmVuZG9iagoxOCAwIG9iago8PAovVHlwZSAvU3RydWN0RWxlbQovUyAvTm9uU3RydWN0Ci9QIDQwIDAgUgovSyBbNTMgMCBSXQovSUQgKG5vZGUwMDAwMTc3OCkKPj4KZW5kb2JqCjE5IDAgb2JqCjw8Ci9UeXBlIC9TdHJ1Y3RFbGVtCi9TIC9Ob25TdHJ1Y3QKL1AgNDQgMCBSCi9LIFs1NCAwIFJdCi9JRCAobm9kZTAwMDAxNzgzKQo+PgplbmRvYmoKMjAgMCBvYmoKPDwKL1R5cGUgL1N0cnVjdEVsZW0KL1MgL0RpdgovUCA5IDAgUgovSyBbMjEgMCBSXQovSUQgKG5vZGUwMDAwMTc0MCkKPj4KZW5kb2JqCjIxIDAgb2JqCjw8Ci9UeXBlIC9TdHJ1Y3RFbGVtCi9TIC9EaXYKL1AgMjAgMCBSCi9LIFsyMiAwIFJdCi9JRCAobm9kZTAwMDAxNzQxKQo+PgplbmRvYmoKMjIgMCBvYmoKPDwKL1R5cGUgL1N0cnVjdEVsZW0KL1MgL0RpdgovUCAyMSAwIFIKL0sgWzIzIDAgUl0KL0lEIChub2RlMDAwMDE3NDIpCj4+CmVuZG9iagoyMyAwIG9iago8PAovVHlwZSAvU3RydWN0RWxlbQovUyAvRGl2Ci9QIDIyIDAgUgovSyBbMjQgMCBSXQovSUQgKG5vZGUwMDAwMTc0MykKPj4KZW5kb2JqCjI0IDAgb2JqCjw8Ci9UeXBlIC9TdHJ1Y3RFbGVtCi9TIC9EaXYKL1AgMjMgMCBSCi9LIFsyNSAwIFJdCi9JRCAobm9kZTAwMDAxNzQ0KQo+PgplbmRvYmoKMjUgMCBvYmoKPDwKL1R5cGUgL1N0cnVjdEVsZW0KL1MgL0RpdgovUCAyNCAwIFIKL0sgWzI2IDAgUl0KL0lEIChub2RlMDAwMDE3NDUpCj4+CmVuZG9iagoyNiAwIG9iago8PAovVHlwZSAvU3RydWN0RWxlbQovUyAvRGl2Ci9QIDI1IDAgUgovSyBbMjcgMCBSXQovSUQgKG5vZGUwMDAwMTc0NikKPj4KZW5kb2JqCjI3IDAgb2JqCjw8Ci9UeXBlIC9TdHJ1Y3RFbGVtCi9TIC9EaXYKL1AgMjYgMCBSCi9LIFsyOCAwIFIgMzEgMCBSIDM0IDAgUiAzNyAwIFIgNDEgMCBSXQovSUQgKG5vZGUwMDAwMTc0NykKPj4KZW5kb2JqCjI4IDAgb2JqCjw8Ci9UeXBlIC9TdHJ1Y3RFbGVtCi9TIC9EaXYKL1AgMjcgMCBSCi9LIFsyOSAwIFJdCi9JRCAobm9kZTAwMDAxNzYxKQo+PgplbmRvYmoKMjkgMCBvYmoKPDwKL1R5cGUgL1N0cnVjdEVsZW0KL1MgL0RpdgovUCAyOCAwIFIKL0sgWzMwIDAgUl0KL0lEIChub2RlMDAwMDE3NjIpCj4+CmVuZG9iagozMCAwIG9iago8PAovVHlwZSAvU3RydWN0RWxlbQovUyAvRGl2Ci9QIDI5IDAgUgovSyBbMTMgMCBSXQovSUQgKG5vZGUwMDAwMTc2MykKPj4KZW5kb2JqCjMxIDAgb2JqCjw8Ci9UeXBlIC9TdHJ1Y3RFbGVtCi9TIC9EaXYKL1AgMjcgMCBSCi9LIFszMiAwIFJdCi9JRCAobm9kZTAwMDAxNzY0KQo+PgplbmRvYmoKMzIgMCBvYmoKPDwKL1R5cGUgL1N0cnVjdEVsZW0KL1MgL0RpdgovUCAzMSAwIFIKL0sgWzMzIDAgUl0KL0lEIChub2RlMDAwMDE3NjUpCj4+CmVuZG9iagozMyAwIG9iago8PAovVHlwZSAvU3RydWN0RWxlbQovUyAvUAovUCAzMiAwIFIKL0sgWzE0IDAgUl0KL0lEIChub2RlMDAwMDE3NjYpCj4+CmVuZG9iagozNCAwIG9iago8PAovVHlwZSAvU3RydWN0RWxlbQovUyAvRGl2Ci9QIDI3IDAgUgovSyBbMzUgMCBSXQovSUQgKG5vZGUwMDAwMTc2OCkKPj4KZW5kb2JqCjM1IDAgb2JqCjw8Ci9UeXBlIC9TdHJ1Y3RFbGVtCi9TIC9EaXYKL1AgMzQgMCBSCi9LIFszNiAwIFJdCi9JRCAobm9kZTAwMDAxNzY5KQo+PgplbmRvYmoKMzYgMCBvYmoKPDwKL1R5cGUgL1N0cnVjdEVsZW0KL1MgL1AKL1AgMzUgMCBSCi9LIFsxNSAwIFJdCi9JRCAobm9kZTAwMDAxNzcwKQo+PgplbmRvYmoKMzcgMCBvYmoKPDwKL1R5cGUgL1N0cnVjdEVsZW0KL1MgL0RpdgovUCAyNyAwIFIKL0sgWzM4IDAgUl0KL0lEIChub2RlMDAwMDE3NzIpCj4+CmVuZG9iagozOCAwIG9iago8PAovVHlwZSAvU3RydWN0RWxlbQovUyAvRGl2Ci9QIDM3IDAgUgovSyBbMzkgMCBSIDQwIDAgUl0KL0lEIChub2RlMDAwMDE3NzMpCj4+CmVuZG9iagozOSAwIG9iago8PAovVHlwZSAvU3RydWN0RWxlbQovUyAvUAovUCAzOCAwIFIKL0sgWzE2IDAgUiAxNyAwIFJdCi9JRCAobm9kZTAwMDAxNzc0KQo+PgplbmRvYmoKNDAgMCBvYmoKPDwKL1R5cGUgL1N0cnVjdEVsZW0KL1MgL1AKL1AgMzggMCBSCi9LIFsxOCAwIFJdCi9JRCAobm9kZTAwMDAxNzc3KQo+PgplbmRvYmoKNDEgMCBvYmoKPDwKL1R5cGUgL1N0cnVjdEVsZW0KL1MgL0RpdgovUCAyNyAwIFIKL0sgWzQyIDAgUl0KL0lEIChub2RlMDAwMDE3NzkpCj4+CmVuZG9iago0MiAwIG9iago8PAovVHlwZSAvU3RydWN0RWxlbQovUyAvRGl2Ci9QIDQxIDAgUgovSyBbNDMgMCBSXQovSUQgKG5vZGUwMDAwMTc4MCkKPj4KZW5kb2JqCjQzIDAgb2JqCjw8Ci9UeXBlIC9TdHJ1Y3RFbGVtCi9TIC9EaXYKL1AgNDIgMCBSCi9LIFs0NCAwIFJdCi9JRCAobm9kZTAwMDAxNzgxKQo+PgplbmRvYmoKNDQgMCBvYmoKPDwKL1R5cGUgL1N0cnVjdEVsZW0KL1MgL1AKL1AgNDMgMCBSCi9LIFsxOSAwIFJdCi9JRCAobm9kZTAwMDAxNzgyKQo+PgplbmRvYmoKNDUgMCBvYmoKPDwKL0czIDU1IDAgUgovRzQgNTYgMCBSCj4+CmVuZG9iago0NiAwIG9iago8PAovTGVuZ3RoIDMwMTg4Ci9UeXBlIC9YT2JqZWN0Ci9TdWJ0eXBlIC9JbWFnZQovV2lkdGggMzQ3Ci9IZWlnaHQgMjMzCi9Db2xvclNwYWNlIC9EZXZpY2VSR0IKL1NNYXNrIDU3IDAgUgovQml0c1BlckNvbXBvbmVudCA4Ci9GaWx0ZXIgL0ZsYXRlRGVjb2RlCj4+CnN0cmVhbQ0KeJzsfQl4FNeVbgmpN6GuajDYY1tIIpPJm8dbJhkyb5LJTIaZJCaYRRvCwTEOjmNi42DAZjGLpNbGamOMgVgJGGMMxo3QvqKltQsBXuKQxFlmPEPGkziLd0BSd6vfuefcul29SOqWhBa7zldff6VWdS237vnv2Y8k6aSTTjrppJNOOumkk0466aSTTjrppJNOOumkk0466aSTTjrppJNOOumkk0466aSTTjrppJNOOumkk0466aSTTp9Y8sI2T/KulrzFkrdL8l6SvM2St0ryOvCzGb+B79+UvG9JXu94365OOul0Ywi42/uO5H0RMcEueZ3I+7Q51E1848Tjf4ew8I6ODDrp9Ikixt20XWbM7noqpq/U5GoyulqNrgajq9roLjW6qozueqO7xeRymnpeiWEHX8Lj6VeO8X4GnXTSaZSI0MDzG6P7kqmvxfJeia2n2NpXJ/fUTu2ps/bWxPXWwKe1p8rqqlP6auT3q5XfOqTeCwb3a0bPRQMTHi7rcoJOOn1CqP/fTe7XpvbWTXO1Wl1Oub9N6b+g9F9S+i+qn2Lngq3/kq2/W3E1w2b1tFh7GhV3t4VByhUdFnTSaRITCQZuQIMm2dMoA5szfm9VPM2Kp0XxtA68tSj9zUp/u+xlEKG4Wmye8xYmJ8AJ3x7vp9JJJ52GRbSgey6Y+hoVb6sMUOB2Iho4ZU9zOJviaVI8nSA82NxVcn9nDLMqvDneT6WTTjoNi7ydzBjoaTN5Wm2w0LtBSAA2B5WhWRly8ziVfic7mO20yG62Y2Tehzd0rUEnnSYlkTOxv8rEVICLCkGBh/E7Y3MPlxbwM2BzqgcLQGiyepqM3B2pA4JOOk1C4oBQbfK2MlOAp0nmS3+YEoIfIMTpgKCTTpOaSGXwtpu87QgIPgkhHEDg6OFpZsYHTyPs6CqDTjpNYmKOQq/U/4aJWRQv+Hg8HEDoV82PbL9N9oDK0GqiwGaddNJpMhKJ9/1vmdwtSv/5yADBI+SEFuZ/dDWC7mCi3AeddNJpMhK5HfsvmNxNtv7OSFUG1fbYIgMgMJWhycQUEB0QdNJpchLjX7vUX2nyAhR0RGhUVCUETytICIqn0drfpEsIOuk0ickHCCj2e5rURT98QGhGQAAwAZWh3Ui5kDrppNNkJKEyuJqm9bfKPAIBDYaRAUKn0tcgM7ejLiHopNOkJWFUZF4Gpw8NIpUQvOcVb1Ocp9ZIdVR00kmnyUi8msEFs9dpY+EELb74wwgAoU3p71Lc9db+ciNFOumkk06TkRgg2BEQmqZzQAjbrugHCN2K+5zcr0sIOuk0mcknIbTI/hJCJF6GNsXbrXgb5P5G3Yagk06TmHjZtLdUlaE1cgkBAYFlStbH9bfqXgaddJrExCun/ZvJ23gTS3hsJc9jJIDQJHswD8JdbfXogKCTTpOZOCD8yvRRXRyTENowUwlDESKUEGyuBpnnMuiAoJNOk5Oo6JmnxOQttjIoaCcbghyB25EkhIuKq07xtOmAoNMkI2ZUPyR5a/VyoIy82diF4Uist3o6Uxk6IjcqIiB4LyneBmu/LiHoNKnIbpecdsQEKgd65dPeUMBL2w7F65jpBwgRSggMEKrlfqee/qzTZCIABNiuPGfoqzG5f2pkmEAdyuo/3bBQfou37hZWej2ShEc/G8JFpa9S8TSYWIGUtvF+Hp10Goq8KBj85ED0mw7LB0WyqyXuWvX0vs5Y9wUjb1VWi+3JPpWw4C23eStuo4DDYbodL9l6q6a56xAQnOP9PDrpNBQxu4Fdcr9kuFZtcXUrni7F3a30OpXrTpuryeJujiHdgZUU+/TZFrxnzaz2civWSGkapoTQW2F11eqAoNMNI+BK5zzpcoZUu17qvF9yZLBP2Idv4PsIedZ7AuuNlxi9Ttn7uq2/nenLzMvWzVjgWp2lp8ncWxfDbQvvsm4jnx5Y8J7CUqutsg8QIpUQLio9JYqrxqgDgk6jTMCGl+dIV+LZ5kW1H5Z2QAPavGgFoGMOrWYb/BnOWcvYRO2vNbGcvg7F3SwzaxgLxUFLWhdIC/Ifz8VeazP3UrcR76eoejCDwWNSf7uVAULjMCMVr5Va+ioMDBBqx/t5dPokERm+Ge9LMU1fNJ9bbC2+V675lnImTa5dbi1ZGVeTHOf4mqlhLjsG0GCeUxpKXGCsfQ4XQYfR7aTwG3UyEyw0M2nZ3YGwcDb2Wqe5902DryHyJx0WGCBUS5FWYg8AhKtnY3tLsOtr2Xg/j06fDEIoiP3tLUrrV5Tuv5Pr/kU6Nm/G0W/En1yUWJw66/TChNKM20+n3vbcHbfsveOW08nTX7x7ak6miiCDnpiaBaCs0e+09rdQ1j9Xlj3UfqgFZ3i34mpVepvl3xfHfdwd2/OWUQsLn1Rk8J5GTGiz+QAhIhsCGh8+LLa6ivX0Z51GiViIALMM3NL6pcSz82eVpyaWpc4qTU0oSU4sT02qTEusTEuqTE8sT0soSUkoTYH/JlakxjuSb87fZnl0L1coBiAqFMY2Z5IvEs8ZBAsUstuCybytcm+78k7D1Gvdlt6fmPp+GfMJhgXvYclbKHk7sHlT+BKCaNTSong7FW/9NE8lGmGOjPfz6PQJILQGxFUsSHrpm0nV6bMbliXVpCdWpAEaJJSlJpSmJpbSZ0oCg4I0+C87pm7prOLFclHaEIBAaOBlQXRuvgLK/aJDmTMAFpAp2lCJaFGutVqvVVh6z1tc/6YqEZ+scCb2RKfY+Hg6ZB8gNIdRIMXJG0HCiHnbZW+FKobpNgSdRk6184GjlfI7QQAAfmcgALIBsD+AQBmAgNgQE1BIgAOSapfCAfLJ5QwNjtw/0Lm1gOCb8MT7TtFwxCczwKe7Gc1rHYqnQ3G3KT0t1utV5r43zK7/MnzCwpk4ygEgtCkRAoKipkGxvOnLDvVUl8f7kXT6BFDnl0BfUM59fVYJcj1jfPwsSyHxQN3ovyn0L9AjZpWlysfuYxrHvvUDndsPEJwaCSFAMHaqqrFaQIwpEQALXQowi7tdBmmhp1rpbTe7umIonOkdp/RWt+SczI42zsUOf5VhKEDwa+yIlVU+wSqVTuNAAAggIZz7WlLxksSKVGYrQEMBSQgcHEBrYPsp6r9SEqvTAR+UiADBX0IIYSjDZoW+JmUUrg+/6lQ8rYrrPAtn+qDC1FNvcmE4E6DBK07pslNyTE5pQUgI3nZbBIDQrKgF29mRbvh81eh16ICg0yjRkSUMEF5ckliyGAEhlVsO6TNgI0AA5aImPZEBwjKmMuy7Z6Bz+wDBKZHZcMicPnUF1MACOuhZgnCr7OqUe5vkD2pN7zab3m1nsABoUPuS5DwVZljEBCIOCKzxawRGxQAJwQ079XrrZ51Gj/bNl+zzlKMLE4qSmS2xUgWEsoEBoTSF2RCYyrAMfjsYIPi8DPOwcqCs0X/DUpNFLWIGCy0Y4thO4UzW90tMvz9n+l0TUyIADS5PtsRqXom91ejtikRC0AJCKwCCVe8Fr9NoEgKCfGThrKL0xMqhAKFMBYS6pfGlqfILKxgrHlo90LnFRO1voN7lspB4hzSdaSe/sK6LcCYP6BGd8vUm69ullv8os/zHWZ/YPFlYg4/MFRPgW3+3iFSMEBBgQJpNei94nUaNVJUh4cwiBAQWbzCEyoCAwLwMZ1ewMgeOgQEB5vwvMZeh0+RuUnihMCd3MkaACaFggZ3hvOJpswIs/PHsjGutsb1v+EU5TnAGEYDg7bBpchnCBAQ8slVxN9n0XvA6jSZhIIFyJjUJcKAqLbEqdTBA8EkIGYmlqUpNGgtqcg4YhwDkbUADQqMJhFtmHiT3otMXkDB8WCD3ZTMur23Kdaf8h6qpPW/Euv7LNClggXdzu2TyACB0hRupqCpTiKjtICEong69XJJOo0cICPKZtFlnkhOq0gEThrQhwGfSuYxZpclKzXwEhHmDnJ4BwiUGCK4mW/8lHpfYL2Ah7LphPl4IgAVyRmBTM3er7bpz2tVzM3p+OrX3v9Tg505pYob18n6vNSZvq6ZAypDWFfHgLQQIMIx662edRo8IEF5Ove1McmJ1elLV4CpDKnoZUpPqMxLKlsi1YQACBhF56ox9LWg6a1fcFKvMZ7if5TASw4J6vBoR7W7EkmJdirtN/rh52rv1067/NLbvpzzInyVdVk4sWOApHsdNzO3Yyc2JQ0sIzbIPEDoUF+zU6W2bdBo9IkBwpCS9dGdidRpsLFJxAEBIUN2OSQ0ZCRVpyrlvMDRo+8ogp+f86JDcFyy9jYrnVYWp/60YctAk+9Y7WhnDExU0m8odKrO4McrR26H0tSu9rdPer1auV1t6qwxUlIl9dk+UugFcQqg2AYIxp6oKCINjgp+EAIDQZPVU6plNOo0ecQkhZVbRnUk16bBxCSG0ypCqAsKyhPJk5dwd0qW5gwOCRDMf9WXXr83Xm2RXl+w5zwyMzMZIoUfq0h+RYWFA80ITwkInO7+708YSq2usvfUWj9PAbsOpbuPNQdyGcBFVhtawHbJaQOhUXI2yu8KkA4JOo0ZcQki9HYQEAIRqFRBKgy2KfoDAjIphSAhEwr53/Wemt0psrH5al83TqVZPapQDzAJCNh4JLLD9DmZvdHUprma512l1tVtcXQZetO0lnls0XuTrCN9iFdrTkGYEX2BGC6vE2Ntk85wzUWlKncaZqNQYC9Vbz3zxAyf9TWhSbQjxjuSkmqUaQBhCQgARIhyjoiCOCZek668YP74w9Q/OmVebbH0XERa6MBAxABacIp45Qljwj3JkP29j52clF9qUDxusvU6Lq8XADHH28ewTQdf1dJtcTiEeDN2rxQcIVImxAVQwEztV5zg8gk5+RAVCqMI4sNXl1dxONLmIAOF0SuLphUl1SxNVQEgYREIoTUmqB0BYooRhVBTE0OBtrJqIsNBTavrorPzWsaRrTVbXBZu7g8MCRtqosgFxSiSeCA0s+BZcBgtUtK2TfJTW9+uUvhqzu0yt5XiZx1CNJVFHeAYIjYomXmsIrcFnVGzF1s+N1n4dEMadEAri3r51Wt18W3Ga8vx98okVlvP3ISDMC6OS0EQiBATrqZT4k4sAEJKqlw6qMqhGxfplCRWpSu03wwcEIg4Lbbxpy7UGyzvOWIdD+lN9nKtbBljwnkdPRKMaY9CsMTyGLTAIngoRztTCFlbMo7Rec1r6zptdDTE84WJs4xa4hHDe5G2y8o7wYaQzaFUG3gu+xURlq3UaN3r7VmB528Uvfq5iMYvuq0iLL02+pfVuufFu0+t3qF15wqkxNgHoCKurHHfsrpufW5hUm5FYszSheEAJIUGoDAAIZelK7YJIAYHI19YN83/fPhH9X2eM16tir7bG9jKrAqtC7O1A86CTxyD1DwcWfNVXNJoIQg1WZ+rvsPW2Wa+2x7razO5XY8Y4nIn3e/13U18DcLcWEAYznqjWElQZLiieevhTlxDGm978nHRprq39H+JLUma3fCupKj3p3FJWWKwsVTqwwFb9j9affJajAQjVYRcoHh/at55VTPrhvbeevJM9xaCA4AtdBkAoSZdrIpYQtMRl9cu8d0PfcUPvWXNPeez7lcrVVpbbCBMe/XHcARECFsIIXRAA4v9zLDfUirDQqbja5WudFtebJvfvVFioxbu6kaZ7upAbAMFpI40mLEBo1gDCRcXdYPXogDDu1PCvwAVy1YKEUqwdhCWGYCcRtsrUpMr0mYfm2dq/YLn0N7xAMWDCsZUTFBbQBiLvfyD++KKk+owkFRBCqwxq6HLiuYxZ5YuVyoUMDQD0RkY8I1Ldek6brnbEveVM+rhN7muVPZdYSB4lL3DfgQYWtGVVwuAjDbtRgaYmrF183ubpYLnV19rMrl+Y3a8YeBtKCme6MXELQkLodU5jEgI8aVM4NgQNIFxS3OdkT53uZRhvKsOEoNJkpm5Xp6uaNcJC3VJWK6A6HZSI6S8usB3PiH0hnXEN8F35IunU8gkHCwQI+x5IOnanFhBCSwgCEOAxy1MUHAc2GqNEHBMO8Z6w19+I7btgudZmdYESccnGEp9bQ8FCGN66AFVCiyQsnKkJw5mYJ1R2nZd7GhV3ucXjMPBYpjbJ2zH6sMDjELqYDaG/RXSEH8Lf6g8INned4inT4xDGmyghqIhVIGSAQNXGqOwYC/MDaYFhAqjks84uAWlBKULDwqW5wHqxFzJmXp4zgWwLBAhPPnBb4eKkcxlDuR199RASy9KUs+mDF1kdHvFApivcwuDujulrt3zslHtZMVJYylU9wuempPjnCGAhhB4BbIjVmVgUcZfMSi7UWV0NFlcjOiidmBMxqlGO5GXwAiBUogek3WcwjEBCqLN6akx66PI4kwoIiSgh+AqLkc0NYKEYa5jXsFwhUMwTziy8zb44tmIxzIA52AlFevf/MHyYCISAEPfEqoTDCxPrMhKrBgtMStBUTEpggDBE1eWREC+zjD5KYEP3azF9nZZrTda+TtnTbaPQAp7CwEFAE7oQZlpEMCyo4Uwsoum84uq0fVQb19dqdnWqUY5vjlqzOZIQvB1mVke9VdMRPiJAqJc9jXpy03iTkBBKUgkQqFA5igopgncYLFSkAosB+8CSGu9IltYskLsWSd4MhgZvpkpvrRy2RW40nwUA4XjqjKNLQEJIDFNCqE6fVbZErl/OOz/eGOI+SgELlyT3pRhXi6WvydbbZvN0y9RIvb+Zkv5Uy0CkudU+cNDAQjPK8B2sB6Wr3fpRQ5yr3eLuNIhmc6PzdF7J8xuLt3q6hxIew8iADgAEV4PiadPTn8ebCBDOgoSQKiQEXoOUqpdrYQGUiMpU1u6kbmlCzdLEM0tmtC6K+9lSJi8CGrzyBdYtcRyjHFF/sVZ/hakM9aAy8GzHhKBcBqqzymGhKj0eAKEbQy+uDFhkdVSIw8LbvDYjq67QZnDVxYKm34OWQIpCBHZ2+7KltD6FMGFB5ElpYKGFRT5jOJPN1a70NFg9l7EGy3ujAAscEH5tvnpuhqfN5gOEsCUE76s2b51aIEUHhHEkFRASKqjcKO9iEGB588FCCbJSBcICrMJVabMAFpozYkv+gbdTJKvCuBgW8LrmVxM+e2DBbMCrQdKfS3n5ZXjYhIq0xOK75NYHGSBcHgszKWOft3DzqumTPzP0XbZ8XDW1t1NmegQFNXFY8GUO8ijoiCwMTk00FMFCKwZSorTAete+PoWElpE+EQDCr4ze2ljWADq8GikBRsW+aviJUa+YNM6k9TLUaGwIWkxQo3xFvRGSH5gdEmChfllCeWpiMbPPxxb+nencV8YtnElc0T4vAcBtyJqKHPpSZpWkKGcxxMIxdn4THrrQiRsylOuioafJ8ufq6VfbWQ84TxfAgs3XONK32gpYCMOv5wwqwwI4Q+FMryjuBplJ6YVMbR+JbZ8HPPzK4C2bynSfrrDqrPoCk1oU70XFWx/bT0VW20ZvlD9lNIVRNGxB30cDwf+GPgXGIShVCxJL0N6uBYQAUYF3N1DdEFytYH8mVaUngrRQnppQjOFMFf8U9+pfcd68nMFqFY6Ng1IDQayEWsXAZdiFZoTqw2fKM2xnM3gex5iTX1ShXeppMv+70wL3cq1tGsj2LL36vMJtjKLgGPGRMDUMvRAHwUITxQfKPedkz1nDCJ19/OZ/afRWx3nbrQwQwqizKlyTHBDq4rydWO1Bb9s0LIqKYvxuNptjjOZog9lgNBvMZoMB9i0GE6NoQ8zQZwEWvjRXKU5NAr5uWObrgsp9Df4MJdqi8eZHXGygXyXVYDgTRjnesvcOm/NvLb/8EpviYxbOpKZoWU/PZ2HYZQIQBsxswt4NqbPLlistmLgB+s44kbAqUGrSv70e89tXjH1vxr7fpoAS0d+FxUub1TJrzYGhC2EYFvinXwYBsGGDMvJwIA4Ir5u8Fdb+TllTZzU8lYHlMti8VVbv61gs7p3RG9ZPE0VNmQLsH2MyASAYTLDDMIF9mhhEwE6MJSZqSCEB44vidn09sSidAQLjo5QgWFBje/yaH6X6jqE/CRZqmXk/qZLlREw/sOCmohVxFSsonGla4apbb2g4E5cQ7ErVfUkVqQkaSSDY58g7PCIgxDsybL/43xMkXyMgDcHVbehxWv7cGtfXinmU57FHTKsfLPT7DAVDw4K24TKVJeEBwyMofs7vtjXW62BZXSwNMxwbglZlOG/z1imeV4zkotVpeBTN2d8EsGAQn0aTgcAhxgSqwxCnAPacx9yF049+IaF4yeymZUz+r2B90gNgwQ8TtOZ6rXkBYAGDA5MwDGB21dJZRSmfKfz6zBNLb345ZS6GM8m1829UOBNxtCNDqV8+C/u6DigkiCCEClaI9bPV357++t9OEEAg8oom0Rhh2Ndk6Gm2vN+i9LbYPN1Us90HC8JsiOAwpJlR8ZV/bFXcjTYGCKPhgvSeUbwlNp6XHRYg+FQG0DKuNVpcTqOe7TgSMhrNKB6YDCgkcBxAQGDfG8zB5oXQlM14YVbnVz5zOjWhMpUFLVdhI/UKxuB+0kKgG0IVGPiyq+rmxUwax4QIjHJ0LPpMYUa8Y+msM0t5ONM7fyeNOizA2Sr/gZVEOJnM+r0KvWDgVEfWu6E0+baKxX/R9Y8TChCIGHdUYhqCgzkC+s4Ze+stV9tjsfCCIso09QtnRBj1FvxqLLTILvjt+dHpqOgtnuZ1TPOGLyEIAymTVeSPquNcTTogjIhizKQsmDga8I0rEQazYWgJgcgr3fr2rbCCJ1Z/M74sefbZNJClGSyABlGdzrqmamAhMdi2wGEhlfQIn3mhmC3BTIOArS4joTgVWG96953MsMBhYfgJhqHpBDZvenlhQgkZDNVezwGwIGynAAhlICEsmHFiwCZu406MR+qxdzya/lznYq43mf+7wvpxi811UQZY8Hbxoo5D2vH6hetBbbEKmCDEg5ECwsszvGUzvB1yJIDADZ5w/yBdeH5q0lWGYVPUlOgYISGoaICWBBPZE4xG45ToMBwNSIAGt3Z8GdgTVvCZpffMrFg+u2wJW/FB+AdYgLWewUJyor+0kBhCWkj1My+UYDgT67SYhkmUGbB2w1XMv7yDhzMBJrBKLKNkWHAwhFGKvjmrlEVcD6QyqCJNMrV+BkVm+o+/Nzo3cMNI1HwmaeH6ecPVdgtLr262ui8png5rvy8kKTwDI+oO3lbFW/3ZUQIE2fvCLcz+eSG8Xi0+z6nsbVa8dbdM8H40E5wAD2KMlhiuL2hMB6rKEM0AITwJgcg5b2blnTLl/Tntcafvn3l6OeuCVJ7CygtUpTHLALMtJPvceX65DymDwgKch+kgLO2oKn12aTILIjr/VTIDotVRkkaOCljTQK6Zn1icOgggJGoBoTT55hfvmXCZmwMQs/79BA2AWH7heuvUq07r78struY47IYWaVcIBITLoyQhnGDeCta8KUxA0IRTepqt3mr1NnS347AImJ1kAxUKTCQhxKg70SZTVESAQARoULlaOrGe/PJxr35hxsW/jXd8Ob6CBSokVS+lCiqUC5mgcn0CKeYqFISwN6p+TBbFBLBQv4xFOZanSBkZsfWLzTV3MjRwjjicqe0rDBDqvhFPHeFFElNooyJJCKBTJA/3emNEAa6HP3fEvNdg7OuO/dipsHzqizx9IFxfg9MfEEZLQnhW8h6TvOFLCCIwu0VxOxVfHQkdEIZFHBCMZEPQmBFIZQCZwWweDiAQUfBA7XxiT/nnn5lW87+BZ3FVTUtAmwBz4pekiAilxDLh6RNRTEJUUBMKSlVYKEtNqmJRjqBNJFWz1GPbi/OsVZ9Tw5nm8MILkVL130uX5soV/zqrbAlLuygfIDapVJUQakAVSoZ7G+Yo3XgKgILrb5n/6LQ47VJP+7TeVsVzAaGgRVMSIfxuCLg0u52yttn0iO7zJSy16udlGLLfK7dtssaOp1Tbpg4IwyIGCGbB/kFGRbMZAAHUihFdwz8I2bT3priDSTcd/7vbSpNnYWukJAxQ9IkKIlBBa3gMggUezoSHsQYKzEyRDiBzywt33HT+7+Lems1LQDvnRSoqTHPMlQrn3lI0LxE9CAMHK6qAgLaRWwq2T7SqkTywuVat1uiV+n4bc/0Ny7v10z5qU3pbZE83VkGhgmxqTbawko61bscWlkrZ32UUze5HdMNeqooQUQNo0QteLYYwGW0IMTESCwyOnhI13PV3NGhKTEx0MCAYNTKDwTJSQBBE7JLN96f+9MvTm++8+dSSpCqWzpCI6QwJ5WmJpQGhCxr9PXQ4kxrlWMuqM4HMMKsy7TOOjBmVC6e2f4mLCpGEE3+mcO7cwrlJJ+YlnMWasUNJCKxqXHnq9KP3s6fKzh6dsRoZ8dSnX6qpT3ap76Kx5w3L1bLYD1usfSzHQfZ2YXEkWuU1AcmqpS4cfYFxoheb2nvaMQ7hF6MBCBkgIUzznidPaFh2DB4OATv1ppHj0rgQk8PNzGRnkSwxUYbxggWQEIwWCzcgqM5HNV4RvzTERk0ZJUAQBEzjoMYu9tiXvnfTyeXAv2zBrUqbfS5DLMpqDzU1OEHVIPzCAEp9Fj8BC0lYnSm+PCXh5MJpjfN40ZKwMeEzJ/+eAcLL/5pUvARONaSEwEq+lKcozz6IcDfOgMCToz9Uw5gdkqsmpqfU8kGtfK3V5upkhde8uPiKmgl+XafDKJugDWCmcCDWUREkBLRVjvTmvWwUPR2a5KYwJYQ2BDcnAsJrkw8QgGIMJlqLDcB4kjlmyjjAAgMEozFGmBONYgc/DSbJaJSGbUMYhOB9vTVPcvJsoJkn7rnl+ZXxjozZuOAmkZuyMo07HLVpEVpYID2izN+8QDVRa1j8Q1LDsttPL7a8eDfvJxWePWFaOTMq3lLyjYSzzGCIcUehEh5FU4ZzGbPL05Ti9PHKbCIKLJ/ildw/iemtN79XO9XVZuvrUtytQeVTtFWVwvQpaEsqYbSz9xWbu0HubzeSejLSR/BK/S1GT2e46c++XK12AASrp2USpzrGaE36bN/EpIWxhQWW0chjkFQhAWWDGNXSKMEWZqTiMIisjsiqc7BU0fTi74L+PuvskqRaVlWJuSmx/7IPFijKUeOJCG1eoOBnVkc9nZd6hu3U8rDuqnwR8zKULI7ngBBaQvA1ZTjHHKnK8/exS+y7sdVRQhJTxb4jeUt8BdZcP4/pvWS5Vg/agdyHEUdYkUxt5SagIOyqCKF7OjThOt4pe502rvuPrLQpr7N6yeShom0RuB3Z8UxCaJvExRCMRnNMgKcPdHmLBWDBMMUYPSawAICAqY4m/2BFDhHwKUlmKWq0VYYAsttnHlodu2cj7My9tAomltz0beDiBAYLzEfJYAG7MGuVCE2S9cBxC4AJjctmnVkkn7ibOQ5e+lZY93NyuVS4Sn45PaF4cRLVSBlcQqjPSAAJ4SWUQ47cqPppAxEzEdyPmIC6M4OCFssHNXJvu+y5YGPVk0QJVuKgCAuk+IqraOqvsnbS7QwN3N3KtTrZc9nEUyxHFohxGc0d71SbWMWkNrWVWzhehmYm/DDJp3USAwKPDTaafII6Z0lQ6o1WyWqIMt7oe5gSExMjAMGoCVb0AUKsJI2JxGK333rqsbjyLQgLc2FmmC98dUb1v9xeDPL/sgRYqavSqSi6WtMsVIpBqS/SOAGLMrHijWdBYFgCEkhiSXihAiogxJ9ZTFJKyKJJCVpAqESV4YZVWA1JIgKHzIZ/+HF030XLh+dsve1WgAIP9ZdvpnVWVGOOoNMT/cTHcc28/hKTN84r7k6l77xytT62z2niNswRV2AGQLAjIHhbmZHQJ5aECQiNVgYIzskNCDFGnlXEJQRt9rHROE2aFg0LdFTUDboHAASDxaIigJ+jgaQXPOpGXT0EMVhYHvfGIqpZBJ+W179wU/WihKK0xOqlSRj/zFZtNdDR55oMZlVWqQCrQJcs+dyp5LmFqz7/XHiAgCqDUrw4oShZCwiBZRU1jR2TQGUoGSNACAwq6Lb89pQZ+Oijljh3i9VzkZnXAvo1eLRMHYnNsF9TMcndpHZYBijoUj5umQrP+scz2MNllDrDXkaV4Z0LJm8LiyvQ3nCwMKOt2cL2QVxxWie1ysCrEGiseWrWoYkXJcAQYoAFCQsX3AhYiAJAiI0lYYC7GIzBgDDmxBwQSdJbNh5L4JXiXv3bmxq/fnPZktm1rHfk7PoMzqeh8qkTtYBQlT6rNPWvixbMLZw71/H1sK5OoctVdySdWZRUl87CG0JVYvdJCA3LEqpuuIQQUPyEBRW8Zbx6Me73dbdcb7X1AWtcULztLL4odP/HoUqlCaYL0eXNyasNeLqUvnaltysO7ue5LYauk1P4XY1SyDa3IVwwuZttvvYxquWTB0s089JPQvHp9wGC7OlEQHh1dO5njEm145mEbKAJHjZplYhoLFMgMf6dEhU9qrAQHS0ZjVqVwQ8QTOMECERezptS/depRsGMkoWzyhcmViyZXZEOzM4CmHnxpcDcZBUQUrFYQfJfV/0LqCFz68Nq/TATL3pr5R23nV2SyPIvREf4AVSGhmWJ5WmzEBDibwAgcL3gCg/acTuj+/7D2Psz84cN1p52ua/Z6qFWsGr64TBawYaukNas9oHFCmzurmk9F62uN6Y2vGB87uloFvM12h5/0n08lSAhyNoC8oPfOQ+H6MadTqzTMgkBgVvzzGROxE9EBmJDkhBImxDqfDRGCklxUpQhevjhxAEUAhBMPs8jsyGMH7GEiDulE/eQO2/quXm3nFkY7/jy7MpkWLVZeECZWLhDRgiogFCS8j9q5gMgfL75q+Fcdo5z3jznvL+suCP+pWRmH/ABQggJYRYCwqzKpf+rJD3DkfGlUQUEJo0f4151FlFwdkpfueF6Rew1p+XjNsWNZj1KQHBzXtZ0bgofCoJ7v6qd4gFqPN3K9Talt326+2Ks+1WT+8+s/StAgf0GFLmkNIT+QkNfg0yeEXezWh62KdQmule3KZ5Xld6GaZ5zMUxC2DPKNzY2BPo7MGM0ZRrSxm2MPtlArNrcD0gVjQAWLJYog2EUYAHOYDJF+xsV1fRn9udoPGjkRIJB7XxMmZw39WTGTSeWxR+Zn1CRPhsdkcCnvnghTbRSSJUhoTj1czXJcxwZn28Oy4bAAaH8joSTC9mFBgUEsiEkVqf9r5KlowgIvpaOqob+UUM07L9bF3e9U+ZQ0EF9mlSNQM0CjqSro4oAamASQUE/9Um5IF9vUa7AFWtj3eVGbbbCDQr7IUDwHIxhO53Y3r2TVXtj1lF0l1APKd5Jqg3vswX3X1WuN1tFXJN31Q25vbGgKVMAFkwgAMQYYzQWRYPP0iiKm6k+CC0smM1TYgzhVjQKSRgwiVCgjUZQ91kiw9jGSlH2NEABYsLUigU3lS6+/UXqK53BEh9q07Eys9aoGKwv+ACB9VQqTv6rsoy5l1b9n6q7w7kFrjKUfyP+1BItIAxUQg3jEAB2RkdloAKhvNEh8uDv66OddunDWqvrguzuwH6LHWji0zZu1kYbRgAFfl3b2A6ty91KX6vt7erYj1vN1zuwPZMdEyIuj0UEILtWkcFTZb7WYL3WYu1pll1diuei0ndB6T2PWzfb91y0uWG/RelplT9okvt+bfa8F81GLHsi5ZMMi6YgLDDuNpi47qBGJqixxCYhMPAUAw4LFtgAT9jPw6mXHkRReF1NRRQ/3SEm0mIIIyFgw450qW0R1VeZUXnnjKoFs04vSChPo5ZqrDVkGUKBqiCEcjv6lH3udqxbmng2OTK3I8KRXLwg4cUF2EdmAAlBvQcWqViWOnKjIg8rels1GnilPzSaCwulq43WXoz/ISggadkn3kfaqS3YckgnbGc2SWCxvg7lvXNTr7Wae0QDx2LJe2rULIdhDQXaTl0dhr7XjB9dtLzqiPtjjfU/HbG/Pi3D9quX5CtFyp8qrD89NRUO/vmPjH0XDJMxf2EImhINWoAUGxttMBiNfrVKYoy+GEKNR4BbGGB/itGIeBJ2uTOVoqawSKgYEYlk8gcEgynqxoUpCiJbAUkFl1bNrEmNL1+cVLQYGJ8WaBAMMEs62Rd0VBpsPQhqG1ecnFiWltR0V7xj0Ywz86XCuTOPh+dlwOousmNR/MlFQ0sICAgJFcm2EQQm+YUaFrLP939uvuyYc80p93QwmyEJzIFQEJ4bcXAoYCFGWFMRVuHeTuX9RqWn2dLXpkLBaLd4DndAnNhx/hIHxo9+FfNui+H9WuO7tcY/1ZnerTW9X2t6r9z4k93RXI66NGo9ZyccRXODYTRK7CTMq0yqyvMmkxYfaHGHDWAhNjYWYCGCq7EoRIvBoLUhmAQgRN9oQKD0ZNVWEFefPLM2jVVdYwpCOoYNo1QQCAWBreISAqCghDWWBWVhNiuslDaz6avsKl2fA0wI665woZdPpSS+sDjRDxAGSG6qWzq7Kl05PpzQZa72Onyhhh++brhUIb3vtPa1sUoFnjZZQEFAo8bwbQX9wVDQrEJBO0CBrbfL9pEzrqfC4mowcM/mOEGBb2SAx1+XvL9Th4ju6pK6OXnqFgOEo1gu8pPdzDEqirohxMSYozUFzVQ7g1/YQIxPVOCwIFmtYWYkRUUZYqVYg3oSjUCCfg3jCKqjDE5e1auIYQZTW746ozxldgmroQr8xQKVy9MSygKruAfXZfVrDKc2k02qwjyIyvTZdWmfKfy69TWszPxWUrj3Rq0qTybfDipDgFGRF2FIETnaBAhwOeVHD0Vqec/Olhyqpe7qCcNHZ8y/rp7+ETA+izoWrRN8VYxUT1xE7gNuXtAUP5E9FHjcqXg6ZNd5W0+bta/b4u6KEVYLEg8mAnE0IKNKG4s4orgjtl8reU+g6XVyFK4bFYqizkpGo9FXBplzrp9z0F+DMJO7MCqMQKaoaIM0darG7SiiILjhYpRtCP7FUsxFX48rnj+jZlG8g/kHkzAKUe2FNEjldl4SQS28lsIPACjAKqwMEKrSbzu1eEbXXOtvEiKuqIaAYD2ZnHTsTupFK3IoQkoIIMnEl6fIkQOChBO+97+NH/3U8ssK6/VWhVcKalEDb3yWw+F5ElUQUFUMpnFQtGGb7OqwXW9R+qqnultNXEqBzwtjZDmMlALiMz+BFoOwCYUFbnWkVdvXVsmHBmY/wwJ8WgxDd1yS0MsQF6f1YmhTHUfTywBcpimnpvzir6dX/5Nkn5dUifXVa7GDG2f8wJZPfjwY1F+eL9YVqbPr0PZYlfrZ6gW3tvyz/PO/Hma72M4vwd1aWu/8i+fQqFjJBZWBNhYMWbFUPhtu+jNN5uefMFT/yHTxdOyfW6Zfbba62hQvJiDwHs2+pJ4IcpF8UNAcAAVqiNEFJnW4OuRrLZa+V2Ndv4h1Nxu4B+HKxIICr+gyc0UNygrYqBjUEdRuJtKdjxlFRcdEYfGiGBZKZOF1kk08hkFT28QUweJOigmTQMxaM6YqexhH5NOUJC6rg2pw4h5KQ57a/qUZXV9MOLkw8RzLCUJ5Oz1Ry18qp/unOYeAAl7FvSyV2QqwksmMsiU31S6Ydu6OETWP5s3o7TfVf4tlYVejo7OcGTa1Gyk1eN2UhKI0uWYBV4KGHBKczz2vG/7zpNLTgVLBBRuvO8T1gsCui2GZC/wNBb6OzyRvdCu9bXJvh3Lt/PS+16b2/cLU9x8xIvB4okndTFwRIKBqVR2l0f/dZfzP9tj/bjf+ui1aJFzzA66MNPl68hLry2wwGgxmjUfALOIWRFhj+Op/tCiRZDT7ZAw4c3TYbZuCiaAANtVWMPVH37vp5LeYYl6eloSpi0wwKPOVQPHFD/jZCkJBQUkKcSUZHOC/SSUp8uuf96ujOOwlA354hdk54167M75oUWIVq/o+u2EZsyfUZWD9lqWsDnxDxmfqM5i5ozTt5rZ/iv3t7eFclDHgO3ye97XJ/a9SdVBVHtDkFYbvRBgk2pDtoyfxY6f1zXOxVy9Z3L82TnDBmw1RJWfzvl/F9Lxm+lk5s5O/dUxq3z2Dtt/uY+/5d+XGay+bei/EcNyonCimj7GjKIkUAYPBQB2XuItBWwMN2TkiQMB+rzwIQZPZxMBheIBw66q5t56cK5IRLHXfuIkF7Sxh62zNUibY1y3FWojJiZqKqaEs+X6KA9kMORQAY9ayiKB4R8a02m/ya1EFxZHH1IIwg3LC1LpvzDizNKFoYcLpxYmnk28/vfi2U4tuP7VwVtGShJcXzzq7GLSe2M47wscf5k1zSp4ug7vJ5n3V5g7owhyelWAwcwHaDHm0YQfLUP64SfmPOuX9S+arr8WIxKgJiANEPFrbKfV1GXs6LR+ckz9okD9qlK+1WXs6bB+3Kh+3sQ1EnZ525cNztndr5T9VWK93xPZRlVfnpwgTyMAYw6IDfNnKfrVNfBELppiYCBZ3o9kXlSREBQqRitiGULhq2irm7p97aRVs07v+5abqhfFFrH8TkwcqEBCCoaA0NRAN/AMRmeWwGKGgMpVKJgIUzC5bcvvpu2c4lknYAVZ67fNcIBkVEk4Q57wZ5QtmVS6OL02dWZJqPZ1ifTllJmzFi2Wn2joq7Osy8/glydNscjVit7IIfQeBQQVOf8thI2JLO8YVXFCuN8nvVCsfNcZeazHyRirvYOGCCYsGqgrjKre8X830qb5u2dXGDClerLLo7WYFIb3YqZZKx7tbWS52T5fybs20PqdFSBefbCJ/QbTRIhKgeByjNgfBKAwIuGMwhONlIIoxmUJKCMZIIxVhYT2+AjBhbuGqvyxc8lf1y28/m0aGAtbxpDotoZQav6rFTEIEFfgaKfqHGKUmUo0U1hI6NfFsWnxJ+qyz6VR4Da4o3Yge8XDCYyspRgIuNOeyWqwVtzn4fUTNJdmEfwUlhEaT28kiD0W1gUgTEPqdmoAEKlbQjCdsAyayXW+RP3DK1xstvU4Dr6BymasqE5aE6OJusrhaprOwTGpE24qhmE0o+QQlN1HaBYuxvAiDYHXXmz/ZugMxNRPpKarZPwFKKyHw4AT60xxZUpKmQoumbRNWaIkYEBwZN5+8e5ZjOVvNqRULlkvlfO2reKZpxeIvFfhBAYYkMSsBOSWr0gAKZhQtm/HyXXMofOjI/TMPrb6xPdSOrbzNkfEXlal/UbvE1PotqfYe2ExnU01lS0wvfEH60V9JYRdaFlYyj8PohkneruoI4fVN02KCHxQ0YUlSFm0o97Rb/3BOvt5lYdG8lxAKankMzwQnGhxPufF6jc3dImOQNlV+UyWokOPQjI8Po3Ge5Ttcq7N6qjG26pUJjX4RU1RMFFYy5IHK3GZo0oQR+ho081Ai1VFIlRMiqqZiMMb6AYIIaTCG7XZkSnS26ecPTW/ZmFCMQQXYZ423QisRMQNcC/CVSBVSgX+NRCqUivFFaUk1GUllqX9ZfMfM09+KO/4dJg+w0OKMmTe6QpEmemoeJWCyftN2LiTQnxJWlQ9TXxCmPEnC1S3c0iXq5Bd+B+yXhIsmxhcpbtCpO+X368zXy8y99QZuZKvCEL4JDwVE7J4PRWMNdhsoU+5GbTVFmUtEvvQNRYyDQEgvpX01WLjf4e3xfqRRoSnRUdFGSbKqTZnNIlhIxCIaNPqC3wExGI8UeW2laJPFIFId1URL2EwmE8t+GpKEEu31Midg010sAaE8JTHIkxhY4CgYBAgcSpKZD4L599MTqtISTi6c2T3X+urf8PrJhx9iiskYVC+kVlNnvnjrc3fcVpR+W8VCpXGZUrdcqfuWXLoENtvBf7b++PMRWBQvq52JnPNczVZWJYwnLIeWEPwMBWpYQr8IMaLahu2gQct/rrNcP2jqy1ajDTt5rcXJQrwSQo7B2xqLNdV9TRk8KhRobSzaTjGi1RSr8HbB5qqXPS0xFOE8eSkg+kjrTFQFAJPIjNboC4yLmW0B2TYKwCQq4pxHtTUDnMdo4D0a8E+TWZLlqHAyI7AFfOxPvpVQkTzbeRfvphQUaqhRCgK1A020YQpPbKxg3888lHHz83cr1TycicU13WgFgQhlgNjuv1fq/qdkl0BPSUSTJgg/CY7kBJZ4lTyrNDmhePH/KFsyo3ZBbP03wrkrHnvvZQzr67ruDCEhaHqlcSgQ0YZuJ3oQLjAo6OuyfVQd13PZ3FceQx2wvft4IYXJRRSB3F9qcrdZmfrj11RuCD+Lz1HbyrozuBrjPO1GliP25qTUGoCFKYGIxycLU4DRV6UkoK6aQZUTosmbEB0DaBK+CTGAGBBFR/vCGqdO5TcWExNFfRmGpOKvSJfmKiXfSCzGEsQlQVDg1+c9yFDAO7CkMEUDzY+zK5KTjs27qW2Btewhv7iCsXm/cLnKOwEQbilJSypPY4pPVXrSuWWsmOq5DN/WsIz5O2CrTIGbjN2/bsjQZd6YGNOcfZ1MB1WQ1TmvxhW0ygAFvW2Kq8P2ntPW67C4ynnmL6sDMG/ChRiFSczQ4WC2Vlb25JIQD8L0vcpqaDf2gG6R+1osIiVqEhHjYh5UYIn2K2koSh9oDAW++GSNYzHaMBbpyUPSS/8q2ecpZxYkYt8lTYdWf6mA91gJijakuAKWRIxexWMrp7+yiGIFJaf9htTqGoTIs+CcZzu7MOHlJUl1GcwuSu0jsY1UQinbEtl+Kk+kqlsKzzX9ue/xvjMD6zIDAIJPQvBVLtKkJfpBQYf8YZO13jHtvaOxrlNGXiBokrY31RAvr9pt9uBjqibTcKs/cQ0CBgrVqHcd00RI9mQhnsxoRvncz2UgnAU+m6GvMjMmRMdgoaTRhYIpqLNEYfJ1VPSUKEOUFH4W9RFWQEA5lZyAZc8TS9S2CP7lCwIjk0tSyOTIpAJ0Q8xxZNxU/T3kmQzJO398FjxUSSzHl848NI+JAVXprKFbYM1GTdBUCWo6LLw5Le70t3hthwHIDxCcGkDwgwKhI6hQ0KawcsfnGRR0OuSflFp+VopBOBKO0+QvECQJF8NPYnnuVRgdqENoDTBcHYq3e5q3fJrrJLaBPjLeDxY2AftFo6pu0HoKhIQQkH4oqrKz4kijDAXR0TGG6BgLohPcUjSWeYyxxEjTpChDeBYJyhc+y8IMGCCotkEhGPg1VBLRhhXYgbEGjk+Od2TMbMAV9tIq6d2HJO9qNtfHhY7cz1Idn7+LJWBWpmtLLnPxpkykP4uyiqwWa2JZmuL4F8za+MJA59baENxNWpHA31zgRBs7VQvsUFzdyseN1t8Ux/2pwvxBJXMmwjhdXo01VcZyZG48eVrgqdFvItAyXD+sLACh/6LSW2H1lCMglI33I0VCIoNAE22odmTQdF8VKY0IBcOpkzYIgVQAFzLyVClfpQV0Z1hYgHQ4VkoChCKQDRggiE7NmpaLwpMIUMC18oTajFklKXOcGX9R9SgwCYsrgPndtohhwjhSJwME5dzdidT0Qe0Fn1CWGignECzQTmXarPLU6UX/LIFE45w5EKPyyGGsm8rYvwXbIzbLflCAjZY8naxKUt8F5VqD/Mfa2I/qzVcbDVRo8XKh5Dw1plrUmJGn2QobxmtFVgFGKyEwxapqmrsKu8tNHpVBwvhAtewAlwqEeCCqoIgoo2G4D8IhkFOA69U0SV/0sugdYwvnLCogJBAgCDahNu4ECxRtSHEFdRkJmI5080srbj6xkqINYy9snElphuNIlNbktSvFd4uu9KGysAUmpBL6kYo0vXpBbPX/5fkUIU8PaHAOrWcVRrczjrcvdPqggDFCF8YVdMtXW5U/VViu1Zl762N4iJGDyxifVPIBgmgaNTxAKJvmrjNPurwG0exVLW5g1kgIaEMwq3EFN4wAENTAJxMXDGiHCy2WaNAjhsQioTKU+SQEFRYoKkk1FFQtjS9OTTi5cIYjI+7Fu1mIkd0u71t/w6MNwyQKPOj6spSRAeoMNZ4eKOVKZGJyiagi7TPli+TGr7HR6PzSgFdoUEOXm1EjCIg27FRcnfL1NvnjqqnX2829HTG8UNikCjEaNjE0gK1DuFfCVhm0gAAqQ+U0V5V58kkIwmbIw4E0NZFimUXvBrVvCyD/pgwmgVFcYUG35hCnwKqkSilWPlRtCAkcClIw+yA9sWJpQnHqjKNLpv/4O1OPfofnDe3aLD3x2ISAAiIEhKnNf/XZAwtm16Vjy+nkxGBlQSMhCNcqHJxUkW4rShu89jKrYHxJ6q82MmXhFZsbK6SxNRFDjHo7p/2uOu76T82unxq47+CVT0W2Djcqvh7rblF8cQjDkxAu2noqZHeZcdLZEIxCGDCqeQqwxcZKLFhoStSUMWqxKsyV2mAnjUnTMjQgNPwrq1tevYCxRu1S5pUjgxvZDCtYPM8tL9wxrWRB7Ol07kYEkeDYygkEBUQECBcTk47NS6TSjoNLCL5CDfCw6QmOZOXMUICA9cz7Wwxe51TWb+VVNKq3W3s75fdKbNfeiO19W40rmGAljG4o0ZN6us2s8Up3pFVkZZ/bsV3xdsves7G9pdGTy8sAZNA0RIg2mqU4I9VRv6E6Qojb0ICAgWdTmgRKRFvCyIAuTmWBSaWps8pTk+qXJZSRdz6D9V6sTJtbOPf2Y2nWgw9QPVUefjzRoIAIAcH4i1ukwrmsVlJNmk9CCGlDEA6UUszlLFoo16DnsXPAYuyiE1PvK7F/qJA/7LB90CT/1hH/cafc+xvTBC9dcuOIxVo7pP52k6fNCjJ/mI3ghYvBI9rWs+RH21vHVOPt5FEZoqJZc0emKRiM0tSpUUaDFD2mOCDIyMOVTaLskrbQitEURsIjph4rRRkgM7N27dgNOak8Ff4z3bFkRsV9HAEoP2giz3MGCMywqXTPT6rGRvAigiJkEILWqFiWfNupxRbnP7KJeGX+YBehEmpvx1x7xXT9p6aPz0/9+Jexn1ooIGKlEQEQSkyeVhsLTGoSneiHDknyuW7xG3cTiFsG7tCZREZFVQzASonjGW1owMwm4ezwdWwxoucRhIQhbw/5Pbb+jptb/vH2H92Z6Fg0oyI59oUFPBBn7KMNR0LoZZAvLEwo5y4SFRMCFYcErduxgkUj3PQcuh0ZqoRbWVFbwuhTiAOCeC7DWaO3DZO21LrxohXF4JjgEw+6AEzi+puxKfwbn+ohHR6BeqJCgdnXaVottwKbOfzCy6SAN3zFUjePZwe/s3oiVvAcnGrXs9zqsu/cfnYJq+9UqRESNBaDBIqvUGOzMbw5WXmB1ZGWSsKqnsQQ4K2JXsJozIhrUo3R3goWnsSyOBvVIpNqsrMv81GTAulXOw7tD95zACkG6v2kU6REKVHMm2DwpUuIhMpoozk6nPRnIvK/izpCr3whzDpCE4vQATr1xWXxxxfxxo5nk0NbFDUx2JjBkRbb/g32yMcm4VNPACIZ6eKLBnc7qxHd30olEfyMh0GfaugyhnB4LyiuJlt/UywTD96cVPrChCKWxcDCk6J55jVPhcb6aWGjARFF8gMUjGJtwzEmNblp+lP/NLuSmUaTWKhVMqv8VozJTXxLmVWMgZcVrNzrrLJUXOQk6Z2ZkxIGJwCRAtW0n4mjPc44z0WM02iU3Wq1NFZASS2AAF/S9yywEzvV9rN0D5vXEc+Dwz8Z1VHGj6IoCTo62vc5ts6OCURY78V85LOwm1SzjEVXVrHoSpbrVLdU3eDPZSwtujotqWrpbRWLLW//zdglaH9CifTLxsemOO3StQ6bG4M2Yd0HZmcs38qym/tb8LNVIRDov6B4OxR3p+zpsr1bOM1VFCsa0umk06gR+R8b5yhnv8p6ylSmsrTHihRWvqmClY1lhV4r0pOqMpJKkyX7vKldmtYwOg2XeDaoXXq/Ofq9C6Y/V8f1dLD+171tcl8z2zwtstupuJtlV7PcC9+0Ktc65Q9bFXbkaxbXW0ZRt1knnUaTfF2f7HHtaUrZN6TCuTOOfiXpWArgA2zTX1wQv+/LM0q/GVv/FWPD/8N5PLE9qpOERJwG69LyX4arrxr/u1D6sMH685PmK5Vx1xrld6qtH9TL79RM/cVLtg8rrL9/4ZaPz8X2XDDozhqdbiyR9xDDEiS73XggedqRf779+fkJJxbd9uKdtx79ulK/jE1f4WfUl6VRooCQjA87Y/6YZXj3qPE3zxreKjNeKTde7TR++Evjh2eN7z0be+2QhccgXdbRQKcbT2rzqRBxFNSi5fIcyalrCqNPfrBAoOvFWFe7//fZvFuTjsc66fQpIWL8y7A52MaFAccnpFqUTjrppJNOOumkk0466aSTTjrppJNOOumkk0466aSTTjrppJNOOumkk0466aSTTjrppJNOOumkk0466aSTTjrppJNOOumkk0466aSTTjrppJNOOumkk0466aSTTmNAdqTNmzdnZ2fvQoKd48ePO51Or17m8sZQRkbG/fffv2/fPhp82Dl06JDD4Rjv+9Lp004wCcW0XLVqVSES7MCfgAZXrlwZHBPoh+uR5s+fP2+e3udoCILhAjSQcOTtGoI/Dx8+/MQTT9gnSyNdnT6J5ECCSbhhw4bMzMwcpG3bth08eBC+9yKF/CH85LHHHtuyZQvNZ5jkNJNXrFgBkDK2DzGZCDCTRmzNI4/Yc3O3ZWZuz8zMzc3dvXs3jBv9a7zvUadPIxGz19bV2XNygJ0BDUBryMrK2r59O+xs3Ljxx0eOACZcvnw5GBbgT1AoSKiAz3Xr1uXl5cGXsA+z+tKlS7quEUwwyHPmzIEdGDQY57Vr127avn3j1q2PP/44jDmNIehrAMg6LOg09kQmguePH7fn5RUUFOzYuXMnTMfdu+FjJ37m5OYyUfbMGTgMYEH7W4KIg4cObd6yZeXKlSAqrFmzBub5gQMHjh07Nohc8Wmm1atXAybce++9MKowtgU7duxEi81O3PLz8+E1wOeWrVtJ+hrv+9Xp00WkKRw6fBgm505k/9y8PLGBNAuwkJOff+LFF+HIzs5O+hUtXmfOnHnhxAkm6RYU5Iif5OTAJyxwJ06cgAP0ZU5LgJAAlTQmuTjU2gGHQcvLzweIyLTbNz/+OEDrI488Mt63rNOni7gxC40GAAhZdnu2xsYFMu0OQIn8/EM//CHZGfx+hbN67xNPwDSGM4gNvnwCvszL215QoAOClrKzswETGAjv20djle0/4DB2MJgACOsffXQV0njfsk6fLvIBQl4e6AvZuO/b7Hb4MgAQtFZxAJB84noxt/FXDCLs9jUHDmzDHR0TiGgAMxyOHYcO2cVQqzvZCAgwnoDDOiDoNC4kAMGuBQTxZShAAC3YjhELAgd8x6u/pbnNtGD0oK0+dGi8H3RCELlsHAgI2aEAARQHAARdQtBpvCg0IIhZGgoQQO7NyMiAT/hv/o4d2oN9sJCTwySH/Pwtu3bBgrh+377xftAJQWRohWE8OCQgPPaYDgg6jT0NAxBo5+DBg1w10OgXAXM7Nzf3u+vXw3fz779/vB90QpAOCDpNcBoGIFBMwvPPP79161YfDvirDDS9t2zZAuqwhHE44/2gE4J0QNBpgtMwAAGmNOkLD61ebc/N3b1nT47WYJ7D3Ax79u6Fz5dVlXm8n3KikA4IOk1wGgYgSOqKv3LlSjiAohco/EDEIezYsSMvL6+5uVkPT9JSBEZFHRB0Gg8aHiAQUajz2rVrQXeAOZyDgUzwzbZt2+6//374PIPxjTogCBJux8d1QJjk5A1FIY+E1RMkaqZow3LgcFzOziZWykYa9XtgAjxtly9T2CHMt3lOpxQeG44EEOinwPgbNm5cl529eufO9fv2bd6xYwsS/TfMR8vGUQp4rsv4RCMZOtJuiMQb8WJ0kNPpFJmGsDMqWd502stI/EJ4LfgTbgAmBkAo/HnjAIEuQU/E00/oHvBPuo0RTsKA59W+JroiXUK8TQdOzjBn40BX8XuJKtEbHBXOGgZRjJkfG/rfA7wFuEP60o5ZwwQZXkz2oW/gX3PmzInUwqZ99pCAsAL4FHeEeU9CfAAacp6PBBC0PAXzEOZ5hiaZl7hs8EfTDlrIR9MOHRxGuVThjBhc/QgS/TbgjRSeOqUdLvrvlSefhI2m3JCXCDmM9IK018pbsUI8CBy2Z8+egydOwGGP79gxWoAgHoHmlfaJgE499phXHVsxkhlII7H0ap9X+5qA7sNwa+1LhD/ur609hLFYw76KpH2J8Fzl5QHTIx6JEsfGgGDJKyoqampqamxshE/Yh28kzSwV90YGt2eeeQb+Ow855cknnzx0+LBdDVKV1OzXIS/qVVcc8exlZWXsHpqa4PsXT56kS9BVth07BleBSzx08ODqgwfFBCAAH+gSIwEEejWZ+/atfOSRH2zf/kB+/g/27t2Ql7dp06Z9+/apPBGaED8Yz9JNFhYWwoRpbm6uqakR85tuD77Pysr64Q9/6Id4Az/O6tWrCQdordyGlAVr1pkzJ+Gl4HDR+MM7opdy8NChcrgNVccffMQGHEOkZwsLX3Y4zhQVlT35JGM6vNUDeKFV3/8+TW/4fvv27SMHBLs/LV+58r5Vqx5++OGcnJxn4IRwgJplXfPMM3Ddl19+mRZTMYag2UVq8vX6C1elpaWnT5+GdwRz79jzz9Mj05xvRnqmsbGgtlZb9iHMCwFrz58/n34ibvoAspUdXyK9QcKZ+9GvTSUmaO2O6KHCJLuKunfccQdl+MLUglcJn3bM+d26bRstRnTbP/rRjw7/8Ie0nwdvFqiggMxrsJuJkXsPPvQQ3Hw4gyNkMDbNnn2W/P50D6CnZ+XksMw4ODOcv6BgZ0FBLv4J38N/6cy79+yhCjyDgPNIAAFGPufwYXgNGzZsYIrD9u0bcHDgT3g1hw8fHkhCILYl+bmysvKHOGi5ubnMQZGfrx23HEz5saMHE54CRniQcRNPCmfeuWvXvqee2rR585o1a7bhC8uhESsooC0fz89GLCuLXs3RDRvq9+yprKoafMT8CGDn8mVY/uwYxZ2F92kvKICHwYcoyMdrwaPZMYR7586dcC9wS4899pjdPiJA0EIBXHdbTs4q3M8loqxJ9Ulhg8eHqUvHw0A/jOGm8KTHjx8Pv3KFdk5m5+ZmYQENO+a85O3YAZeFt0bvLh//JEZYv349jAY8u12tCjX42Aq+g/e46fHH7XgedhUWX5+XQ3NDfYMiTxwOnp+Ssnrz5sFXopEQXei73/0uPNGuPXvgPkR6GrBJAb7co0ePCiaFHXhw+JedHcKO4Rv+kP+qoAB4YRu+mkHqZYl1Cl7WU089RZfgA56fD/dAQe++S+BVWHAgev0KMHmZBpbga6BrDQ8Q6H3dd999NMnzEI7orogT+Nt/6qmBLA9A+/fvpzJNcOfwAxrbAv+HYoFPNOD44HRX69avJ6E35IhRSQc4ENgc5gycMA/PDD9kM0k7YnR+dIsU4D3AT3ZgMnI4iA00B5QdXBFgtDcCo8Gjw4PgUOzQXAuukosTAx4B7m3Ltm1bRyYhwPcEKQzN7PZNOPGA5RjjIx4EPCkNrx2zKdn7gtmYmblr505Yx2GCAbCHqZvQLAJZq/Do0a3w0lXepJysgLGFK2bDmOMLhVsCqISBpdWTloOBLkRyzbJly+5dufJxu72AxhDvP2DOF4gJT1MoNxd+uf/554fUVYdHm3FiPJ6Ts2X79r379tELZagLo7prFwzFdqTHMVOV3jhNLbhDGGS2ZKifQLnIwvmIbFuBj/bsGWQlIrEH5E8YtxycyXBlOnk+rjjk9KdViV8Fv6FJRcfn4fyE26MXQSHHARcaHiCQkPPoo4/CVfbs3cvWQno0dQe+zEX+pesGv26YyTBDGBTAjMKcX1pQstVn4U8EoiIlBePYws1sz8rasHEjxU6L+xGq5XPPPw/ozTI34WXBQKkjlqMdMbiEeC/4mHRYHi3qO3fCGQjeB9GyvaoRiY0DLgo7xIMAI/i/GiZK4aSlmbNVZDgOCxDsWCcB/vX4li2wQOch7+fipQvEk4rphzt2NUSE7pBzUEGBkHUJXgbhBYGQBbt3F2BG/I7du+luaRkKeHE0G0VCN3wSzMJSuB7xnDJigi9EY84YCtcWwOc8VVykIQqcHmpZCfb64NHgMA0N8kTDoEf2719VWLgRFzu4MbifLHVSCX7Znp29ceNGMZ3smsEP2LLxBdEQ5WGc/y5cxAey+wHLbN26NQ9ZhkY+W53DIc+vDSGm4eLxADjNs7EgUvBbGB4gHMEySiC6+JKm1RvLxkm4E2v+wCepkwGP9v3vfx+AlOs7iBtZATzi/zh2fHA7RkrDw8Bvt+Tnww3sOn6cTkhoUFJWtgVmLCJAHuIh3Uz4I0bnJygjZhxIIRX2w4fXrMnFaxFfCJAJ+fZJSoHNjiIiyS0RAYJ4iczVm5lZgFIBv7S6IgzymGIkc1GNBSZl0wxhYXAOIhjfkpm5avNmWqZJXB/sxeEViV9yNKvh3Llz77nnnpAz365W4cPzsbHKU6e9feCrZGsm/E6Uz28QIGwuLARA2Lp3LwwaqAyUvkePmYOB+rCzAdd68Ub8Bl99BX7PgpSHyz0NV0iV52tf+xqBJCkg2QNMs2Dwyfa/B/gdrY8gVd6DVXpGBRBoH8QbuEOCtYB7ACjIw7cDhwlAsOOaC4oGfJ+DhhW7yiaBUwgZOeTQ7d6zB3ipYN8+eDVPPvecpKLBuYYGtlziEgwjxn8+AFMM9CfZ3OAkOeqdkA0t4O0QysEn6EQ5GglEy9qBN6+ZukzpAylCPHjYgAB/rlixgmnWGzdu27wZRp5UngEfNuDBg8aZjAygm2dr5mowI5AsBJ8gbQoZOPCiSFkDIHC2mgC7AxEMpgEMYMDYCkHFjtU5aFQzgx5NiHl2YWzUvD42G3NySCUH7WwYXD8I7cLiw7l798KSRIBAV6dHg5FhEL1rFwP8gBEI+jN4bhOGwFU2btpElme6KE3voqKiHeiZgqsEsIyYbH7Mqz2//z78vACVHQlxPkAMHiEgkBgQ/PbhSxihw4cPi18J/YiAFAYtW/uuxZ37a/r5lDylEQ5pUYOXAq9mF1rDtOIBvZdgkPEbE3UF8WNJ/xHbgahChtxgR+ScOXPgfa1Zs8ZOOVyoI4RYCAQvBDwpjkK2fwWJIQGBSUS7dsE3a9euZWrg7t0kNAZOg4DnDZp42suRUJSHFm9isWAtCZ4UhHwSh/IQDTgEBZ1QKPhcbxJPrV6dRAVmUgOlcs8eO2qUdoQgO/IvPB2Z4wjVQ9w2Mg4V+qML0TItBkHYf+BUox6cQNXIQR0GuNECgrhPGsyAFyHi+UO8I827gE+m+hUUbH78ca2JjGRU7anE8XwqwcqLoyF0VWIisuNpz0/7WSIn0W5fvHix5J9q5LuxGwwIZMfIQ7mInTOId7IRJWg/F+UHkkhz8HlpnHMwdYLZtPPyGCDs2iUAoam5mdCDL+4aZOY2HzQ6kWyZg4O/A0fM752qn2ThBLH82WefDVjIaPRA6N20aVM+6q2ZAW9fO4Zq1qe4mewcf+YNW0I4fvw4DCBofyAIseqLgAZajlMfJFtVTHaqdRpp9LJDPimOMJle4bSUiablI2F6evKppzLxtfoeULPD7WYUvo7eIv5l0FvOQgEMDtuyZcsmKqmhAoKgPC3GaqYHWc9oepDlNlud/GJRBpyki5Kx9IYAwhNPBAKCRgbI1twwDQJs8NTbYdKSxyHoFYg/yeYA8w04S2j39BQAksxJpBUJxIPDqKoDtXHjxkc3b358O1wti2Y+2TMDLsqWPLQ7Pfzww3b/VcD3Wm8wICxfvpzwPxtvhvOshhdIeSevJbV4gB2QITOxPjmVfISZAG8cHpZWEzhGUtX5g4cOZeJsEX4oO/kvCGTs9ky0ZMIP123cCGPL0AYkjQFGzK4+AgkJWkcJadMPrF6dQ3qfBn79ABzN4wAYZNbj6q3mbfrmg2bcBgIEOBYGk2Hg7t3ZGoQPYEz+okkbhetqFgWyq/hNQu28RYKhpvgN8bDkVoDTbkMzmlZr1s75XPTeAkLSPcOLIxenT5nSXDETbxJUFbjQ0qVLtfFUcM8kHgQsvtmqeYfeIE0PJgTAHzg9+PIKgwwqQy7Ij3tpxMYIEIK4xq7qRyTnwDRet27dNpz9QqoJ/mEWspsd0YxOQteFYYHxhOG1o+vcruIMHQNj8MQTTzy5bx98nnrppRdPnXr6wIEtW7eC3pRFBU6D7jMbL5QbytgyNoAg3MqkJNKM1V6lAJVZZgTAJeZRlQBG7r///oceeghGIwflrny0jYO4DmcDhVpA6GYsY04eN3peWhZhTOC0e2HEnnwSPk+eOgUbSH0gdcMiRTZev/VIffwdQuKy21euXEkPTtJC4fPPryKb7c6dWQFDTXyNt2FHZzFI+HAhclvQ/WtZOBwJAS5ai6EO8MbJNZMj1CJ/vub1WnNz4dVQQiVsMD3sGs71SSma9YIWXxhkbbo6TMvDGFBHwmeeWitPe8Pk1bXj2vQwEixt8OIo8ioLV7FgGCHxD44Rb5Bqz5JNgLRp7bsgiRHGcN++fQDRcJ+b1qx5dO3au5Ytu+vb3/72PfcwUyQ8GnqN4Xh4vzQ/xwgQgiQ9/qIRqR588MG77rrrm9/85ne+853HccqFxgTNrCNtVCzcpDXQygiiGk0hWv6ANWDkRRieNnCU+aEef5yE4eyg2SJUm+eee05rxhwbQKCQs7vvvpvxID5IwEiSp57e43HVd6BFLRgNeDpgzB9s2rRl+3YY5AA9C+YIzC4YaoBK8bDMMbdxI3BE8IjRn8yESHqxeDvqDucd/ELwCBnGD/3oRyS0+InEGqVgB54Qrg6aMqxWMIfh5rciAS8XhJQbBwYEh8iRRCgIEEvEJ81AAL6KigpvUGA2q5afmUmYYNeKZ/5M+sADD4ipCPgD8z8fjt+2jXTzAFU0H9FgE1JAZAjJUfesWMHq9AZNSJpX8NvVKLICp9ANwygRN/mOVPEKZhSwCR0WwOnM8/Lww/uffhqekWFadjaPlxjtvPvBJAT/mUPwtT0zkyJyxX3Cfw8cOJCjzhB70FsQpgbxE0ld8shTn4nXgdGA5xW2R5CXKFCfMlbgexAbYPEFZF6PFYpyApY8vFA2NmMKUIrHBhBglYc7f2TtWlgUKJgk+PZy0T4AA75//36HJtuIDKF0m089/fQBeOnbtgW8KWLzw88+uxllTuA7GHCaw/RGHGpqA40Y7ACuEs6QJJYrzP7qqxHjACBsVzuvUZg6PFc+uTMEDmg+SbvPxllN0ZiinQ2ubGvIeZQdMAgDAwJ5NIA94bkoviLL/zVlq+Y+upwddRyHJnWL9rdu374N2VM7e8V5SCODK9LIAJ06dYo9LEgayJLBiyBx7tNPPw2fMKQBgEA71HQmWAWgy8FfMCVAPKDJT4DgezT1YDIkrtiwgZ4FDlu0aBGdfw4Sadzw7C+99NK2oOkxWjS4DUGgAcyNbXjPZOaC5/rSl74UHx8PyyKwDNwkC3tGOSGAcegkJAB8b8UKeNKH775bXB3m6tHnnnvm4MFs9bXSxBDpG5TaBghA7AbSGoXpciEh4FZxg6n48ssv29FyTicZG0CgO38WeBlGTAsI6vH5GEkFepbQarzYwkB0ObSrbmv6b8CbIkB4yeEA/TQzi5FdjYnSBsWRVxGmLozYaiRAUZhdeRiw4Sf8I8HLhfGkuEeyVxCGEIIVBA1XttptYQPqsHY1tA/uHC5E54HLwWuiCDduhhpKQqBHKHjsMXguwYYBkxBm1+atWx+Fk6uVrrXjY8eYarjudrQ10ZTL9mc6EjzgMFC+4DuCU+FcCFjLslAXBmyHYSEH4qFjxzYXFtKWvX9/+g9+8CD6Jojrd2Lv4ACBxI7a3NGjRx1qUMdjmZlsTPwlBG5AQLfUnn37iCvhoQC4RPwtTQ+BgaMMBCoNbkPwaQrw3vfvh8/y8vKAsHCyAzPdFuO1tJNNnIesZHtycwtXrTpcUBAwyelYigAHAgah1syk1dJ/M1QqxMjGXLS/+c0ZdRWmKerVVDEaG0BwqGlx+9av95ng/FccHpsBWo/dDuIQ9ZyF/68rLSUDOy21gyQ82jVEIwbjD2wICyvsLF++XFKTT2m4aIehEJp//ZyVSHBL8O4yUfATOUHwsthChoXrA8xlgo+yBjHXoJ4COBNsuxjEqMhuW5IKtIZBMYw0D9EeS8f/vwULggfnxRdftGNykJ2mh4g90Ly4HMy5oMlDUc2g7DCf++7duQGGKUIh1R4CUFOIQTvUJ3gVvjj4pNB08hMF3DZ9AtRQ2tqp4mIW85OXR36lAB6xI9LCs7OIoN27t2zdSrzv8O+NGzzmo0uDA0IWBcXBC1q5cjumVAS7OWg1X7p0Kf0khBUCeScL2Arn237NGURaGc1e0TdcWCDFs999zz333X//GiTQW3O10qzmWiSWUzDAGAMCPEtdRwcc9dQzz2wTBg3/FSoH5fadu3eTsA1/wmInYSIknKG2tjbcVG6V30FCI9mJRozS02jE7rn33tU/+AGsvKDFwCIVGhBAeMPodOBQEnJo6MjC5rOL+gMCPRpJsMGB4iDUrV27FrTI3egsCBDhQgICnSTz4YfhPik/IuA+KYaHW6Ht9vT09JCDQ6MH0EoqWyBvqpZnYEbKQIHntSP6kRFAO3X5Iq7CEUsmBX0kP3/LE0/Qlrlr18Zdu7bB6KGXgRJ8QkhTOFaU8frD55+Hz63orQhph6QdcpYBRO/C5LV9KDDYVfwfdaNBAA1uVMxSjf/AhvvQIT7Q/cDMBEmMchmCPVzChRrSc6qNmWevCW2M+cKtbLcztXTLlrVIsNjBzWTjpPW7kEZCCEDRsQEE+MmiFStgCfjWffdlorM4O8iuRTdCo0SARm6RzUePPolIKJTxwd+adsQyMBOTWbxxUd6Iti/4/sENGzYiwXD9AAAhpMqAjLYFVlVsgQ0Esw4+d2IrK66J+z+1MGaShhsc5EM3BiehiIhwAIEszJQ1QwmMgWIqNoeFp4M5Ro64gYYFRq+oqChHBa5gxwoFnBMgkA+Rkh1ytV5OjQGBeTazsrZha2DgkeBtm6q+BS8Bdk2gAil3dtRrgNn94kOCpgdFleRipqodPctkoBOy6ODTYyQUjoQAGywHK/fs8WIlnJDnoag2wsngWUfeHMo4CwAEkbMDhz362GNwD3Y17oLQgF5NXj4n2glh/dZICOMFCHNVKxCwVY5qOQmWISkPiAIOYZ6zvg/43skLbx849UPyL8oBJ2D56dgylUIOBIxrR4wGzS+nIAgQnlZN1iSh0aP5PbVmhsO/Hn74YUkVDoNnAvk7fEbmoQCBZGMQ3YFTaFi0QESSFUuY2rr10UcftaMJdKD57Ouwoy5DAVen+MAjmKtFc4NnTPvfp/Z5qS8w+xx4o+CZAOnLrrrCyey2Z88eii3ZAjoantmXMZSjKpgCFtCmsRNDy3LQiAcSF8hdEwcQ9lRWSlgtKuR5KIQmfwC5lHr5ERQLeKdZfRkn/5njxxnGosMoD1OidiKn0LCE3gLQQAMIAX3GxwwQJKxpA6/+gQce2JqV5bNah5xvxMaoZO1Qg8PtWHFCsHzAIGvRwHHmzN69eyllAC7ERkxNfgx3xEIBgl1Du4Jlflph8/Ie/sEP7KH0BUmVIR2RVEyiy4nI7cAgEzs3b8LOI+vWkWo50HymmENaSnZqu3Rp3hrcP3X6FnPDz00s3pe6GIWz+X4eMLVQ46YQVtBQKEZlbV7eRjWgOlsMd5CokE0RaGqgO6VGAqqAeHPjav6HAwhwMwQI3oEB4a677oIXMZCEwP3dmjo2kjq9K06dss+bl4eTZAdO6UDeUV+NdrMHXWKCAILI1CvEOifEoVkhX7rmuejPnZgGC5erxKEO1h1ItG5sbATsZdFNNGLa2LyIRmxwQID70QKCelpiKLv/CGuJzCkZkVRd5vMfg3xCYBcSPOx6u/0ujM8ZpM4AjAzDoi1b7KEkHIoghUlCtbLp/tfv25eP8QkBKCRuOMwtkNTLwcmfQg2FLAmrDx2Cwdm4axeIQ6QfZfn/yg9VNHIyT/1G8elujatudCl8QKBZOpAou2zZMkCtfLII+fOyHSUE0nDtGgkBdugbQgM6xm9k1KHwg+5gztL8Oe6AIGm8h8dfeIHFJKjB2DmUaRg0ONrRJk0fTkt1k6gmgHacOXeo2fEDjZh2RoUYsfAkhJAqA3tqoW6HAgQuwAwLEHKCR0a9EDzsZrRiDQ4I5PzdiYkkPglHHYFsNeyZamXbKaNwzZoCbfhxUOyE767C3nLUCHOmF6jKC8UaARqsRsstBevmY0aGTy4K+bJUolkHCAODtnz58jCrFEZEoyUhrFixYs2aNXkDqwzZaqrXI4884lCjj+DPPDSviRT7bP9pIBJJgiU0u90fDSYMIEia0kagC2zC97hDzSD2Za4FzFXN48CZWT0ENKCRtEmnnTt3rh0zi0Mkn6pnyMWabGJaDjZigwNCqKe2hyEhjAQQAnlB8wk/2bp164r77htSZeBPESAhaN4aDAyFK9tFEAIlLvmPT7aYgRhiGtFGBax279kDMwSElm/fc4+WecUYr0ZTTBZqlyS6aHPEtNNDO1soGV8UixtdTAjfhnDfE09IAxsVAQ3gmAF9W2heI0A4cOAAMcsja9fateH0/tyRq1YVo7TBTIqVoZmDu34JuRMMECRtKjQmNLESkRibtAPnHlmkA8sFqJ8U+0Fl3h3ojiT8XIrR7D4/TtCIsX73ZKXUFNuhUCUy1gXLJ6GNipix4ntqcRVMmhaTNuRUFCpD+GXY+WtFo71dpG75Dwi8o43bt69DC+pDW7cONJ+pztV6tD3u0NoQ1FES9lK7alSkUmD2IJWBDNcsOjcrC7ZtIOKGt21HlwQbc5zACxcuDL5Pu4buvfdeitfNx9DTHCxO6HNKhoLHgdJ2Rk5huh03bdqUhhWYgwGBVoSDBw+SYusLVtTeP4ZgkYIAl4PjT58+TZWOcjHeOHBuUzA81szZsGHDgjVrnlq3jo7fu2cPAK9dG5g0IQFB+9LhkXdjMS5yo9txegunkt/rph2su8h83xiOsgMVEGBSlsBIcf5B85yqeDExbOtWnnS/fTt8Se/3mWeeobp/IbE6ABAc6HaksjAhvAxo5YBFLS0tLaRpi7xIME/WUMJR2ICQpRoVg2OZKA90S2bm47m5qwoLSXcISeT4IDNOsJfBrqo8O1HuIkmGXZcgTnOr3JyIQ82KOmZnb9m2bcOmTesefXToDRMVN23evD0z8/sPPjjQrdpVqyy8IJgJe/fuZXXFMcyS0tZ8Jscg6U7r3KdXNiiXR0BDSghUHfS7mzZJGve3lkhfBr6gFS0wq87OhU/hZQAWgyuSjuznrBdzG50sWbjPEkUffJCKhwvmYvv4TieyhCAuTYGXdOc70CsNrApzOweDgnwOVu0ObnDyzTt2ZGBDCgfmQ9HS5rPZatAgHxN7gQW2q/VXxXCRVDyI8DaI2zFgHhKbUFmhB3GqhwxM+ue77wa2/d4jj4QpIdDLBdSieNeASEUBCIwxyX2/f3/I0aabESldOWKt0ZyKCat5eT9Gt2NRURHV7KJyoIGwnMPrzHzve9+jwVwVIdGvBvcILFq0CNRtOpKFuT71FIzARszqzUcxQGvtzFbHMFuNzX7yyScdoXLlhk1DSAiU2pyfD5D7OLJzSECg7wu0ISX+L4K0nq3bt1O6Iuxvx4hu7r31f/tUhVibmUus7cWIPtjfvXevX6ToBAMEr9qFR3xDsEBH0jx5aPVqeLmZKAkEuN0F14D4CKydceQIYMJ9J0/uxtjaEOFwmJWThawN6hiFdosR82JlqvABgdrQrMbCC4EZ3Oqv8lFIWLtunQNTurSTwatmMUvYMYEMGtqhCwkI5D0BaRCWDFYcM1QAFSvehWxLCcshEZhaMMDq7BsoQer0gJ3teXmHMf2NCkHAVTMx8TlYVWFSHEbaE9Tcc8894aPBI488sllTHUU7RAHR6XQMJUfTDF+bm7s+Jwd+LuoQBsMyTwfAXLlRrIowRPqzyi9U298epK3Qs3znO99h+/4JR9p6PiyDJj9/C0IKTGyR8xWcpkohNDAxdqBQR0WoKMxeZJTbMcZ+oFyGiQAIXrV5UEBlHhAVYLkRt5SHWbfcX+DPNSxWbc+ezZmZD2P0/hoc/OyAcDhNBg1AAV0ahgg4a/78+dlqr7FDmDDrZ+/VnCEAEKhB3gM4LWmR9R2s7jCbp2r8IYlCPCOxNpxnw8MPU0BmgDtvIECA38Jtw7qzQy2/EyAFMSEBi0XvVkt5B89kMhXCGag+iT3ILEAhzaCEHsbkAppOmSB4YMWSABsLT27asQMump6ebh8g7iKYKHeVJOeBgknsqivKq0nSJ2Fy6+HDGbhwABesW7eOxL+AtCkhMpHWuWtgHSpSCifbkUw6sMQ8+NBDJP+I905mK7h5Cs8O5FAVZllRKZRwampqvCIrXJ1vAhBIzIALbcVS4ZTrJG5VuPiJtSeshNDY2AjP+0Ncg0KOOYwhyckOLKuyQ63pEQgIu3Zt2Lp1zbp1qzCnmB4iWL8WUlYeZjeLi4qVaOOmTStXrgxTQoCfwVReqQJvYLClupNH6c94S4Q8QiiCb44ePUrxtyGLyIVMbiJjYD7alLRPp2UB+hVPtTt0CEQRsk7DdeHnFOcJZ4CplR+QbYo7rFA2Rv1JmiQaO6oqoO2S9yEAbMmgIfq/wPFXrlxxaKrukzRIQ0ddBUVxJIea7Bbw9gF8nnvuORBOfvzjH4t3JPo5Smh+eaakZD82l8kNzndQ5/kujGSgZdo+enbFcAqk0DcFWDceMIFqgIj7/z5278pDV0vIOl1UJDYfDVxaQKDn8gMEtaYcSQjwHUgIlHwqKomRPj5QCaBxBAS6CIVVs/xBHEmQ+r74xS/SCWFwao8cOZKdDRvFstqxTtEOrYSgjgOFa4IuuX7DBmAZGHCQAexqiJf2BeVpogLsmMJMvAn8QkPNKpCr0cvB5p1AQNAMVwgzghoWQoVK4OX9WMU9+ITJ+cCqVauxz5rf5fzF3ZCAQJaxPMxgylOrVQdIJnmoRlFmIg24mITEgE8//TRBSp5/YoLYpywkQjLiRBoi9nco5yyVj4azbdy4kcpriytmaxqhSpp1f8WKFd974IEfYCTnCy+88POf/1wcQwbPe++9F2QhuMk1a9YceOYZgAXxIAAL8NZgKC5cuMAtPxpHpHbuCZVhrAHBHxOoTJwdRYLTp0/v379/ldpsIk9UtAiaA8Tjz+GiU15eDiMAvLAdXYd5GnePmKsUewBswrVaJBgfGIFHH32U4rt4TI52wow3IFCCKtbK3UUGakrQg5tfsmTJd7/7XXrFDixmQnf02GOPbQtQGdShyMERAMFgGw4UCYfZWL0zgFOyNQlHRBnqJZ599lm6fz5iQSw2CCCwF4QvIhhD6ACW1ABSB1qSnzl4kLCdlapAq4jWaxaQAx4SEMhFm7djx8NbtpCNPfgxs1WlHj5grh45evT0yy/D+g7D8tijj/KVgvxcQfOQ/GVwWiqhRmcVWgPMZF4GOXgCa4r7AZyXlJTA8rR27doHH3yQfg5z8v+3d229UR1JeH4PPKJ9QULaN14s5WUDQiaYW1g2sTdcYhvDnDk947ksAzYwHoyNbTARl4C0SZTwAgYpL0j7wAP/aLa6vlPlPufMzcbGklOfrIlj5pzurq6uvlV9RY8jygB3bfAnrHGAHlJwEmANHCc6dCIEH+5KZqHdpob8T4yA2rr5u3dpy1DN7KHUIHC0F1R9yL3MDhoE7Rqsb8HEC5JAXISFiV3CmuMujEZNRxJEksSoRJwh1MMukE9QjXlyuTt3/I3n9DQVhL1qhRU7KU4ULKzqHhoE0gqwxyBwNdlnsbWscJIv6rVWozHn3BzrLWzpbHiNGLSCpFoslUja9M4W39+Ba7fRgztORxAJlirgHQbqdb945n+qBPyEmeb3Mgg3ikXPescukfmTB8frOiQ4q/ERE1QCHIybAs+t23sZBCe4zg4nXbcb2ljk+nTM5ICrqypf4iMQxuUeDBf/d5jWI8OmRcqJjUZoAMOjLWTGwX6EupLWdUrQAZpcUNrWJAETVWNufh45DdfX1zsc7UWg5fQ0Z4FxWHLz+YDneahW6T3t+/dX1tbqnLKQ6ka7xLKeOedEQV3TYt68QreY0503COlxnfzC23xwpCNJDdyrNr8WTAfoBWjLOkeCoxdILKQDJCgy1A0NsA0+I54HYRZKzG+jKZBqgUdZ9op2rw0CGQFcKIPgwoHxGCk/eMdUY7ZAJF2tcE7GarjxCaWNI6MbN2h+oXe+efOG3r+yulrOUCPq9McXDTXOGYQx4n1iJRNrSmLphnc1CAVlXb5wIfGKzK8Q+LMkiT6h2Anpqz8b2pxBNj1y+64QtJs8ZfSlS8huFlZYX1KSZQA8MGfZk9DxJmXzxCO3tKhzggMq69atW500vV5yktBuF5V7LSclf5UDnUR6Jr6Lh0ImWbR4UaQjAs6HVDlqDi0hCuxT/Yop+kmfoQmaXAB2rMbL74ipsyt8/aSU7BlrgJmUhskSD15Yj103CEE1ssFcksnRBakDU0ZMvoblQTk9Qg8dOkSfZGMda76niOmmbDCziWHnz5rk10tqleO8+lyDkD4e3KpB0OBuh9lchFaSpIcJJ4a8AWcyqeleutuP4mp1mlfjpL2fPn2CY5KfDXleTrkiyFOzclCAgEdITK/eYicslOnm9zII9Dk6OuqTSMItpGsvMzS9WirPEf+CxUk5fU7YxyAgdoMGUTJfZ3I/BaXHkjEQM+ymQ3i5HKfr6a0lz8W0cx9nImscBegQcGITSAEQJBJn0q8EjcXI1QWDJtzZPMZ0iQGBefRkVlevFiQzYLPZTAyCTKNYWieWhFPHqg5UtftCa8AzMmiLsO+mveqXMAgqeTEILsxlk/nJ6AlPjlVZ7ahOaqGYgMi+RXJInrIqwe9KIe6C5HclIcNPjevAIOD6SdVb31nuEeMPd9yMQYBJz4bJBAYBpFtKfotLZyTlyXw/lsR8WtU4nT1Tv1xC+oBG43IUzfD5AzahqBXmqSyhsaoK/ss2FqfTpeDvtbzE3KZBaOUofJG56cfJSayEQe2Vf7yXPoB+n2rrD/DZS1NXKb0MQiHIdDbLi0N0fRQWFMgQv8bpiNH8F6p81kGd8iMfzyJPXGYU4HQRPgBVJFzu/U7NO+yCdLcpSyuzoe+FiYkr4+MFuUahhTG8CzICjNPqoUYvo+ElXjz4FMyl0g8cCd4rn+wuGQRYV79057AsOId0NwXpv8xqsuNAabVQJ5ewiw8eOOGoj3I3YqrM4fWTk+TsRdbPcM7FDwxCJ8+pyCYhtUII+i6/Qgjj5vJXnLHkZrqfDgtS8jFs27NldZUYXsjAXOMd9pjP1jsmCUk1tQjundjXd7fPQbRsIjH+DrZ4/gwq5C/lHxw+LOQMAvjZHKcsr0gGmeQ4LhBCvjlJLjMOypuamqK2NCQD10CDUJDreGp7cX4e3la10EWtlwnKCFOyr0Ke3hpMTqrLUH4UdCTYvME3O7Oym4vYkXjIQrXomH0bbjabVHdaCU9yzI5mfCYLGecYnrPq0e3vkcRAeRZNSYW2g8eJAwyCdC5VgDAxMVESygKXCbEXPYwlj97mZrl3/AWOXjc2NpDZ3C+BeH+RxON0fTmL0TvY1Ouga0sUXlASt2cMzyzrshN3jnT0Osm5QQ2vVuckaB1PIbIe/tg+t1rwFFpKf/RkXHxfhlB3GAd/3S99FxJBZCaROF0N7CCQWgj2B+MiFJc3ocvLl9mygQ4llr1bSouCN+MuoMYphJIpXiYjfMe78VQqc9KKsI/0qOrixYu4y6sFKZiT4vQzbAh/k3Rm5vr1iIsoM52abqBAmHP5ypWuI5Ra/dWff9LK/tzqqvfHRqeLWchYvHyTsajGjRjhknPT7NzVyxqokqD7bszPI5lOMqnJNWWvpUjyd4kjgxXC9o0aDj4r6P/IyIhjCjVPP8tBviFBSq8WoYOxOcIk+0++qTya5oTfKQwV/sycirSljbgrlfBtU6t5x4rNFLauJNJILndcjyUNNJx6nH4H+6hnGmQ9RzXw5rJQzGEBSQKhVR/uXOh/aVTWJbsfdu7gwO/k8zLQC7mz6nw1qD81TCKVyr8vXXJBggxw7zhZV2SeShpbqdxkr2w89UrCutEuBNWCPlG5jBL9Qbt4M6jseQRaMOO+FddwGXFhFpvh8/9ZGemQTNgX5ZCUjxcANE9VeRNND3iJaVt410NfQORp3v2PNg4Q3eP1dS9wHptojvYRCkUzcQNVZDN78uTJ02fOXCsW68x/1Qi6iX7obfSvvQbpATLmfAfn7YZjJwHufUheGeHCJif6I3Wr8Ykcveo8+8nkmSXy8AdB7Lx9lQnVE09L9CCTpKV6MND8quRmxakmZiU/lXiP2lkdAqqHS0tLOPXFStIrYUY9pFFhi3Dj//r16+WPH+E/NmBsbwtDhj/T2g8rFu+Kr5k9JeI+sW1M34f2Pnr0qL81KAQaDjNIApyFJx5mPd0O8PDxZ1Ms5KdPn3748KHDmSDK7MPsJCqtKjHF79+/zziFqr31MVNgPJZL9gonPKWv/ePYsbDCWI+BxM+Pbp7r4SgCbbkRTs1p911q/n9/+YVqiMxrFUlE6Jzk/pAppgyd0ag6PibqRa6rZf36228vXrzwOZJYMtpflaA79HB1YWEB/mB+McZxIk741cu12rUoOsWe513ZNvAq7O/i339Xbdf6qxpD+ZFpkazHS0l5TKMet6soFJ9l1u0CnzB3H6es8Ais+PWPP56/fEkaqHe4uirKCDN5ebmMLEtwfhuohyGUvYQ2SseYBAx9XU6v57VcjTGPYhCeeZ9GknOr1aJZ6d27d3l5QpgfP37EOhbGLNWEoBOTPuX0Qxc49QkUmzaQhb7s3NvG8AQp58+fpyb867vvzpw9i4SqNDyv8bW3d+ycmChHES1mzqyvx+yHOQx7cKhvNIjAIaOeujigc+y6sNBuLy0vP+KpH/KkauPUHbX1s0+jgQyYvcqKeZOITZB2brvdjjkXUs+n2LEwfKohCwacc+afQiWRly1mh38sNkhiNIqRdwmk4npShyQUA+XmAh/4UGL09+koIoFc5/Bn7+7Saj18+BCX4B2OOVpdW4uCg0Gq/8PV1Z9fvYo412EfqAaeXl8vC1/BFNtJKvEauz1c4IBrWAO0Ai79Bw8epLFFyjODxbMsiclQDLw9DxtLRp4mmpWVFWogyQoaEgk8VQIv8BxTsNLihCx5OOP0LyhTqJMtPy107927R/YZpLLeT4zdHpB07xorJ30HnC1Ii3P27NnR0VEXeFHmhamgryFZZIFDtpELz6sHqwqpPfQ/ZubnI0eOFIRuouubdwTDGwRkj0K0UYFpXhYXF++1WvTzoN1++dNPjvuowMqzpTrjy9p3x48fHxsbo30rFUGzG3XHxsZGJx0P0knn9QNeDUpqk/maon9tuz7Vv6zEjItvP/1OK72fGTROqZfRrmfPnkHBoIFYGg2Um0pAJXbixImx06fJUE9OTVEHURHqtxxG0HSV2LA9xQbh71Li2uPHi0tLt27fnpqeps/WwsKypNLoGtQDe5jB4ELTwwctooF/9OjRU6dOkYZgpFDpz54/pyUZ3ICdZBj//IGDl+CdNB5p1KPvqNBiFFEFinx5AU8DLRqRTQOps0M3sMOHD5OVIyNAMxpESi16+/YtaciWxPX52AKFGtOw00IIlj+UlXYWCQLhctuoiTY8zJ2tL8/nM8po1zwjv/XOFEFfwDfDQdE/PUr+qWHKAiCornYsb9Y+X2JfB8leh5EY4oOGHzX6rEYBaIlqnfINOXDgAA1hZOTcdnvzLQpfFVpIqtJOee51ghgovDPfZbD8yDm41aLxVOblmU7ctnpsD9smWVVZDRxQ24AKajdevieA6BCdtxvtIolh0K2urn4BiaH3qawvVmIGqiEQZhgtuHvAEk4XhxqVvyPl4lUq0i/Tojx2inXZYDDsA+wU67LBYNgH2JJB6JO5yWAw7AP8hw1CZQiDMMYrhK/NIBgM+xfx3bsXlpejRqM/DTsMQsEMgsGwrzHNbvMzzFrmo/gljDTx62OeyVk2CH9rNv194i6npzcYDHsIXKD4xDRkEJrNCjKtS7Jyx4FyNd4yHPjmG/9AjobdYDDsG8AgnPv22ymm7k8FoXAcis8LVqmMnjy51zU1GAy7DvWSqt+8ubK2FjEvB4II6Bf6vOxc4/btc5xNwGAw/BWgeRa+Hx+fYUSlkqfFaDbzXDoGg2F/g6zB3NxcQZLhqvs0EimaQTAY/oKgvcPIyMg0w3F+qMXFxSdPnpg1MBgMBoPBYDAYDAaDwWAwGAwGg8FgMBgMBoPBYDAYDAaDwWAwGAwGg8FgMBgMW8L/AUtJlu4NCmVuZHN0cmVhbQplbmRvYmoKNDcgMCBvYmoKPDwKL0Y3IDU4IDAgUgo+PgplbmRvYmoKNDggMCBvYmoKPDwKL1R5cGUgL01DUgovUGcgNyAwIFIKL01DSUQgMAo+PgplbmRvYmoKNDkgMCBvYmoKPDwKL1R5cGUgL01DUgovUGcgNyAwIFIKL01DSUQgMQo+PgplbmRvYmoKNTAgMCBvYmoKPDwKL1R5cGUgL01DUgovUGcgNyAwIFIKL01DSUQgMgo+PgplbmRvYmoKNTEgMCBvYmoKPDwKL1R5cGUgL01DUgovUGcgNyAwIFIKL01DSUQgMwo+PgplbmRvYmoKNTIgMCBvYmoKPDwKL1R5cGUgL01DUgovUGcgNyAwIFIKL01DSUQgNAo+PgplbmRvYmoKNTMgMCBvYmoKPDwKL1R5cGUgL01DUgovUGcgNyAwIFIKL01DSUQgNQo+PgplbmRvYmoKNTQgMCBvYmoKPDwKL1R5cGUgL01DUgovUGcgNyAwIFIKL01DSUQgNgo+PgplbmRvYmoKNTUgMCBvYmoKPDwKL2NhIDEKL0JNIC9Ob3JtYWwKPj4KZW5kb2JqCjU2IDAgb2JqCjw8Ci9DQSAxCi9jYSAxCi9MQyAwCi9MSiAwCi9MVyAxCi9NTCA0Ci9TQSB0cnVlCi9CTSAvTm9ybWFsCj4+CmVuZG9iago1NyAwIG9iago8PAovTGVuZ3RoIDEyMjAwCi9UeXBlIC9YT2JqZWN0Ci9TdWJ0eXBlIC9JbWFnZQovV2lkdGggMzQ3Ci9IZWlnaHQgMjMzCi9Db2xvclNwYWNlIC9EZXZpY2VHcmF5Ci9CaXRzUGVyQ29tcG9uZW50IDgKL0ZpbHRlciAvRmxhdGVEZWNvZGUKPj4Kc3RyZWFtDQp4nO1dB3wUxfef3b27NBJChxBKQBBpCkFAEQvyExUQgZ+CiqiIPyuKgAUbSLUgCIpgQ7GAIKIiKCgiWCgqTRAQCL1JCyWX3G2b/7yZ2bvdvZJLLgH+YR98ILnb3Zn57ps377158x5CDjnkkEMOOeSQQw455JBDDjnkkEMOOXTOkyC63G63x+Mh/7rEs92bMkSSx2X+VXB7pLPVlTJGgGN6wzYdu/To3r1Lh0vrJ/HPHIqfmo5euCFn3+FjJ06cOPbvvu3r5j5dHzlSoSRo4EkNW0k7NBhJwtnu1/93ElBLjFVV1YJEfsO+25D7bHft/ztJaCD2Y93Ms7qu+/AU5Cr8ZoeikYSGYBnQNBHWZfw2cjkSIT6S0IMArYVrAdpJDrTxkoTuDQOtgsc5AiFeElEfrITh2jHOMhYviejWsNAOd6CNl0TULQy0Cn4Wec521/6/k4iux2oYaIc4XBsviagD1ojyZYFWU/FAB9p4SUDtAFpsh/ZhB9p4SUCtsaZjG9dq2v8cWRsvCeiScNAq/Rxo4yURNQFJa4NW993pQBsvCaiBEgKtquf1dmRtvCSgugW6ZocWn+zhQBsvCahmXhhoj3d1oI2XBFT1OA6F9sj1DrTxkoAqHbaZYwDtwQ4OtPGSgNL2hYF2X/vzBVpRKr0d1nI7wkC7q+15Ai3gKpVWaEDKP2Ggzck+X1zhDa7MRMhdOuAmb7B5FQHarc3OC2hFlPm7b/nTdREqlYChpNUh0Cp4c6PzAloPeo7wEV77fC3yc8nL3KTlYaDdUL8MQSuIoiRJohi6j+pCc7Hf78d4w7AMIhZKeqM1cVkYaNfVKivQCuYwILs2IKFfQKmXFYy3j6yBSjocK2GRbUsXoF1dowxF1CVmNLioaeOGtVIQKJsmIuy8Dvx+WFc0jPc+X9X2fbzkmRcG2lWVyga0Aqrx7NKdJ7zefK/31J5fX2lm+VYUE7eCegTgAsL7h1ZDJYmu+/Mw0C4vXyagFVHd37GZ8ruZxyUKydup5gnDp+Due6ImMHMJNe/6xBr0pQO0vySX2PPPJkmoD85XCGiUNNWHfw0HrY5pOBbWVB3vHlynpIwIwTXNFk8H0C71lAloRXQ3lnXMYtrI0DT8i3mpCnAtHTVcocGC9mT9kjEiBOktG9fCXvmPRMLH/+yzThLqjWWNsSX8VfH3NmhzgqYoA1clqtimZxuQNShuFUkQJ4RAK+NFZSN0WUI9KbTGyDT8rVUgsGXMNHTys+LDeOOLF8RvoQnC2DBc+03ZCFR0oa4WaFX8lVlfF0XXRqsDhbG3TDh381gQC3FNXRENDwPtnLICbSesWKD93AwtWU9Wh0ZhUHBljHPGEPM3nskromfCQPtZ2TDGJHStplqg/cQyMAkts4dlcamgKyoxIkaDhVZscEU0OAy0H5UNd62ErvapqhnaaRZoXehzrOm2HW0DXPJO8MFh1UFmFq91AQ0IgVbF75UVaNvnaRZorWc03GgEqFtwQThwNQLugWczimtEiOg+qzVGufatsgLt5bm6BdoJNoHQwgvrHEMyVORSI2L/0NrFMyJEdFcYrp1QNoJnJNTmSNCvB9C+bF1EJDTKjzW/GgZcysoEXIVYaEOJtuAqMrgiug2g1a3QvlJWoG110Arti7bpKKC+v8hY9TFwrdiajIhtz11YdCNCAK3axrUaHlVWoL1kjxXaZ+2qj4jS757nw1o0cMGI2PRCo6IaEQK6Ccxs3Qrti2UF2mY5QcaBYLbBdmgFwsXluk33GuDa0WXgygTcLaMaFs2IgIj7UGifOReghY2X+J4goYs2W6F9JFRhFwm4ie0mnsDhFzSThbZ9bFZRjAiIuFfs0GpDzgVoKcVlakqowV9maDXtvnC2ELxB6aJRhzC5gLpu7aGbzIggatrulzJjNyIg4t4Ora48evahFVDl+fNvRHGBK6F6qy3Qqn3Cm5kCTI8aT+0gV6m6HglcMCIOjM2I1YgQ0KV2aDXd/+DZh9aNniTjXHp9Qhy2pojqrLRCe2tECx7eYIUHNxL0VC0iuGBEHBwR404ERNyrmg3agnvPPrQu9AkVfos7lQvdio2RRFTz56DWDsZQt2jOEdJI4p2/5RGVQNVDpK4BLlnsDr1Qm0mR6CSgpqodWpzX5+xDK6EF5CWrRMB9e2MaQbo44Iqo+hIrtDdE3/ODNar7vGNkRVPCcq5hROx/nhgRUiF6roAuLFBVG7Snep0L0P4IkS26ImP85U3liJZUdHBFVHmhBVr5msK2U8Houv6jAxj75VBwjW0eoi3sfJboue6o4Iqo3mnNDm3uzecKtDA2PwH3i1uSkegpqswVUYVvTNDqWG5X6E61AHi1m5CDsU/WQxXdoBGR82KT6BaagGqbPBgc2mOdz757xoCWcomC5a9uT0BSEXslotQvzFyL/a1iCAIQ3KSZi4dvjMq5AO720Y2jhTMJKPPfEGiPdDx3oOVTUMP5i+4gYBXJjhdQ8mcBaOEt+ZvHpMsJLtJM/QF/EASVSJyrU859pWHkkBABZey1BH0BtIeuPBeg/YFtrnBwCQN5l/bmKmiMJKCET7DPJBD8F8WoJgvgRax++8+Q80jnm+1W3V9ny8CeMYmRwBVQjR0h0B44o0HhgigA2bRXCX3DD2bzSQlO64JfewhFMCIEwfVBkGvJH18RMphBuEDajYvUoBVhA5cbEW9GwkpA1baEQLu3xZndG4MgTfurd6GPuUAIcAko7MqvXWI3IsgLe9cELdEqaxfFuAO7wHXFnDxuAIdyLigweH+DCPJbQFXWh0C7u+kZhNZ9zbB3Pvn04zceudAys9zoRewPDIiDSwOzfro+hfFUoUSwmRzwRsPATlYrYrQctJL94XGIq9HsKxoTuVrB/RHUKWKq/2lx2EIPdjY8Y9F0AupvtHz4MkuQAGpxiqwiAWcU31Kh5tD3MRoRBNqJFq49VrHIgYgwQRpP2kPEghwKLt03eD2iplpxeQi0OVlnDlppKs6TCfl9stXfJqD7thEBYBoQl3jggpp/c/kYnKdkyRsHrB/g2kNpxYjxBKsra+Q62G/QQrfQILYhkgKW/pNlcwx6sLXmmYNWeIk0T9vNt2UKEFDDF9YS5dJvB5caEV/3IuAWZkRIaAz2BaDV8d7kYnUS9OmMQUsJuD4N2wSughdH9OGWX2iDVsVbqpxBaEeCegSUf5dtZpEB1XmU6D9yKLg+BWsL7irUQnNBbJCJa3ckFLObEulZ5b5faxjbxa2Cf3VHEvypX4dw7ab0M5ZlVUTPsYVGx3m97GqMiwyoWp8FVjlnGBEqln+42xXdiHBBbFAAWsIzxR8WcG6FrpP3WiOZ4KHLEyK5GFPm2HbLVbwh5YyF14roSQPa02EyBYCcS79hFvM3YT2oLoARoeGCn/sK0XynLvREYHsKeOaveLrqIS+67Z/YaroStJZ7InFtkslg4dCuTzhj4bUCetSA9uSN4ZRv8IsmtX7fS13UXBzw9QyMCN/K26TIRoQLDbBAuzqejiLUcd5hv10iROPaxGkh0P4hnkFoHzCgzY3guYCOi43fOAZdM4LjDXCJJiavuNkTaU/FTZ6umATCiuL2kjzddcMiL4fTKmt/kSKh5ZkaAu2KOCOXhdh3BUTUz4D2WOTj7PC4WqP3Y7a7YgKXGRG/dY1gRLjRvYEoUIB2abGGA6pt+Vt+05hVFqIhfBspYlZwTQyBdln8QeGxBklBvkwO7ZE2UWxA4JtqT29WIDyTAYuN/1TCustuKh9OLLjRnRZoFxVdraVsktFvDaYBYOH02ukRnQjSqyHQLo4zcjnr1pqxnrSAfJky3RfBh6N7LgTyZflHfs0nmm4wGEMPGBHf96wQqjG6Ue/Azh9A+01RoRVg1+GCx/+G/bLwrlsNj45kjQnCqBBov43LhSAI4/AfD9WOLY5HQDczY5CYSo0L0aZFMoSkvl+dIosXDd3kk5OGtxAj4ru2Ife70H9VNXDGBqLdi7SG0B2Hi4cTo9Cv2N0zhg9BPdk7IrTohRBov4rPO1PuS/KY1QNjOq4tohvZGq7hgxcUaqiI5IHumz44BuDqAecCs9D8+LcQLciFuvs1E7Qzi+T4AmCvmLDb3JgNWKzm4+3pkRQEAT0VAu3s+Ny1qfOxl3DRmqcyC7fzRXStAe3+2jHYgCJ5oNRuwiFDLJikgvrvdfZ+u1EXr26C9oPYrUwqCjp9cIABGy4uQaebH8d6RwltGBQC7SdxQruAoAXHtdcPrUz00qjiTURXMvVIw/tiO3MN4KKLR+4hUkA1GImOVJMH2KemG91wEpugnRoztLB43TTnCIiC0C0cY5dBxXmTW0SeCCLRqn2WAFuNvNy4BAKB1s89nH8PLR/dcS2gtnQNJ63uqRzr7gossvUGb8U0HWQAXBUPC7GUUcdjZmhfjxFa8IHfuuQUvL0Qjg0oJhr2TmkmRemziO7HQRMD7lPJy42La1P4NirVVrY+mRotSEpA2WwN1/DO8jFLQrrbU63/xiA/UQ3z1VBor/7XcPQDtC/HAi10NuXu1X62LxYWWOo1Pj31oui7SSK6h3owglUZVPxGfNC63sT5GhsO/JczKD3yroCAmrPzRyreXqQz13T7seturJmgnRgKbbv9ZmhHFB6GAF2o9MgWHDb2ywRs7jsXokK26UR0OwHCdDfpYnxHGUTUgSzhKtsgoBtaOQOqRjIiRNRIpuqRhje5inCMiLoW2r+TaxIIMN9DoG2z2wztM4VAS99X5lO7KFOEBRZYj6wih99uggpNnSCiS1UiqwkRDZD8S5Yf7Y74uFZAjaZuD24QgBdl68O1whsRIqrv1Ri0f9k3dSMTOMQqdp2Pmf82AO1LdpZwoewcM7SDo0IrEhkuNh1xMLhDHkaPVYig2D+1aWwxzOITp7CZTr4d+xgjPBGhhqOIaajwHQ84abFxQFY4I0JAdVj0job/iHWjFgIwMvsuAUPBWMaYIHs2lGubbzFD+0gUaMGr7mo/4UhArQu1vFjQzK43WsQeeX/Z2HkrNuTs2rUrZ+PKb1+7MbabohE45WsP/DkILnRp/ZAwx7UFVPsIhzZGpxD4x+sPXAGbD4Hhsw1Jb/9Qrm28MQitjO+LCC0A6+46jQiYsGcaTMCOu6QIh3HguioXZrdt26ZVo2piydTIcxH+qdF3obH7gnU4abFuaB17kJSAMtlCo+GlsTQMz200fI0BrMlk8OH9re1cK6EGa41NVeDavpFCBkinPL3nnDSAteJqWF5k7u19pWXRTjm5TQap6CmhwBm643HTbI3vvrDj2n89n2HVxARUcxeFVsU/FK5Ng4xtPukfy0avseeA8fSQB0go6w8ztLeGXdJBT06+d4mXWMuRgYVNjf0jmzJxVBQSJBcUJXW5SjIxJoCbfNX7hF2ZY08H82nTsErm8QmoxlYO7YLCuBZEcevpBwDYIMfSgYM2tGNA+ZAlW0KZKwJFv0gz3cJAC+pW2qNr/Ny6s8pY3Yj3Iuva4RENUWHG5ZkjUJHczSeepE5k6DRoZB+lmgYooGobuUD4MjrXwj1XzTnFogcNtxfzhpOH7ny8chhlSELVlxFoOan4hhBoYQpVfmYLhDwZTnYzsPQ32sCR4Vm2hGxnm6gKXnvU3kBX/fiw2fknoKrskIyGZ0fzhIPp2WmhbLaQuP4Ov297PC2sySehKsuwD14rgYfIjOvCcG2tMXup2aoHNbkgsDoH9ugoojwWe5ubhgsW895CHkyU0KGbfXRji8xduZMF2sosekeNkoQBpFSF7suwOWiQS0BwnvzzRGoE9Z28kQ+oasYyJvnq2S4TUIVxxwNTKoway3JOHBidiYqZW00QJa5Skp9Kg+fB89l3F6R1AAOiq4k9BVRxGfU4QBKG8Ge6ILgr8+7fuSJv7IyxpYWobX8NTo+8X05UhBm7juYTc8h3Yt/v/w15trSYLQQBN48NWPDf7YSjYsVkWLp0CYmpqalJ8FO8xzdDCI5qJrR+eg/lObLidLFAm/49hzZsEgYaoH3BgDXsUIwlyoOqHOueqMg8YREIfGRd+g98YvCDt17qsjOeC3VTQiMQTQ2Qte2fV4iMLe5+Ful7g+sHvPTujBkz3n91cOdGqGQjQKkyfv27p3iHNdnb0aIKpM3n0IZ4APixgubD/mbHCozVm0EM4/59ULXCDCNTdE1IoI0bva6r4YBlDRDVZsOI+nGktiVW/MsbTQ/eNrl5CWILjuvEnl+c4pFoWPfi/dkWaMt9waF9OQRaALatcRjGyrIw7hUP14hl3C4Po1DWc6GvYCaFAxaDr+DvYXGl+xLQ5VvhQT5OZJLt6FZSZ5sA2OR7fvByK4fN4ZEey3KZPINCq4WkgYAX0OH9fdZTRnpg3CvvrxFnmjOB5q8NK2RV0s9NQxrElQFQQHX3YK+sGc/XNbkAH7q8RPgWtrfTHlthKOMsYmB2pySryEuajgt0jYD+fAjXdpl71HrwkK308Jjf76oa8348GEKS5ApZnwVRWIOtJz1ZA+Cr2/ZYVrx5K4WJmMbbGJ5w0FHAMIpbT6DK+HMbVboEY7p7gfGX1yTYtRj3ZMzcxY9ZoRUECPRS7Gos9a6vu7NCrAd3hQg/w6+i629TdFxAjyUd3T6gVvzreY1T4OQ3TTcQe0c7xXsEB0ZR26SMQ3+1r6+UQnbKBNTkq51HTxzd+pY1GN6FuuoBR38wiA7ez5o7yhUh+5bY8uHxH8/5bMozXVLt3whJ2wLQBoAl/+x8tEpxM1CZno66B5Lj8ncHEjF0A69oBLkbmkzIDSjj4JjPn98eRdC7PVWrV7JziBu9hm2BHPR8k7q2b2LsaqaE2i4NjG3Pg9bbzElWMQ/PI2y2nSjKxc6bZm56VJjqz378SZwSIaHNlHxqO1HXBlkTTizoGGlrl9gEcGzMJt1daKZxuIkzFDi3/H/2SywCP7lQu4NENMMGigoi+wXLOwlCa5h25JctTxayBx0rCegzcI7YsJXx97HvroYhqcPHCvUlGm7OY192jHxkRrL9b/y2gC8xfNx+FfuX9/MURQKKqNw8nBcYGGHJlpGyLsObI3Ni7dCKxTcQ7PRTSB1dgHZlLJEsEUhENwc84ESd1fGRWddHPeCe2aFbj67tbOnJJbSYiyoGrIyVJf2TqGUXM0noqtOyGtitJrPoLcv5KUPW6lwtXDGkaryZVc20OkwuTBn/1SiOvQbPO/iUAayKc6f9h20ORKJef5wgFx+Z19oyUfjxZ7a2QFmKhXeXQ0LRzu1DsXu/aftMw6ssvmLRtYEdVqWm3fLHYrJAYqf19gyu1B2/OZ4iOCzEQ6dz2Pt2BwFJ0U62t1KoNCQLvyUuLXhonzLUd33Siz5uEY0wBV0BtHssB8ck9CtWuQXyy30xB67GSuvDcC2BNh5jlwUm6XCMY/IVLrrxFJEENBKfVsGZKvssaVkMrqXBs9/2qFCMmUre6SRz0BX54YhF0EGhFhWD+rLqzurFSZsYncJz7aZ4TulSaEl//W9nuwpdFBK+YNsARKEcbYV2EfQMmOpH0EiLkXxGQAnvmbmWQHvUIujc6BmaOuiP26sUO3VQFFoVdhlbG+m4dCyUOh8XED32gxahBkIoJS3mm1cqnmRWpl1oNjPFlnaJ9bSznQSU+L4N2mOW8GgRVd9NTLvbowROFZ8EtDDsMvZLPEVwkmZg/eTHTVFMjvmkH1nAvT3UzE00bqJo/NLZXWw1U0Dut2wC4Wg9y7gE1GDQjUklo8faSULv2fVayrXfJBbfzhPRnSc+bB5rfxPnM5vFntpVRI12n1jSrSiZJUJIQC9bljEdHwwXaFo6B7kkNNBeE4taY1Pj0pulmJ0nRAGaiL1UHsi+R2y+zIaXxTlRRTI6fyBMFDSEDSEujGIlEIut8TYUWnPoMmxpPxSXD0GI3RsnoE5gX/iJSbDPlipAKDxLWSEkoc7Yr5lMBmvxgNKm5LWBGAijBzLe1iC+LhSFE1zP/0tf6abb7eJditfiFFHN35nLlBIxubufQWhF1Avny9hMxDIZcebS+hD02vZ7+rknbos1mVFRyIX6YFzg88uKTGaGgueWxnoVmYQJWPP5FZXFQSh+H8YfJ53BLgSyS5UKPwl37Q1y7dTKJVsGrxASkWvQQaqyqyr1POPcYXG5vYpMgsslSVLp1LKFvfJ+UxauWv3H0k+fbhOyW17KRFBs/NDnm0/ShSxv+7wnGpeWOnI2CHRId2p6hQppRH094+MCh3pypTpNW7dr27xu5ZSS8LCfSxRQ38KVey11ska8lh2WPUdIEESxtALqHHLIIYcccsghhxxyyCGHHHLIIYcccsghhxxyyCGHHHLIobAkQhocd0mdgykSQQ4eV0lHh587ZMQ4Wk6uiYFsGKVJxuG1kjuFc46Rp9mV13a4vL7pExeMVYh2jKdECNKLXtSyxYXppdzOWSIBdfx12/5DB/dsmp1hxBGR/xIrV0kuZvqXmElCLees37wjZ9OaSTXLUABRgEQ02wh/6xWICu391fqtWzcsuKd0m3ahV42m+5/94pYlTwRa3QehfX58B4NWRP15lKr2eGkykyCh17FXUVXZhx8om9B+Rk+UYxXfxrlW3IplVdNUGe8tblGrWIhAO57WPNRUfF/ZhHYWO7hiQCuiel4jJ4K/USmyLYF2ggHt/84LaCXUKt/IiugPrWpRcnQ+QtvSyw7QYOyPkqo/bjr/oBVQtVP0PKmuqqerlKL+df5BSz5ZRI8/+WU8tzQ12/MQWgE1XsaUr4VZDrRxUCi0hKpd0//xgf2uqFiqLZ+X0IrBL0uRzlloLelvBRq7DxH8ka8l38Eldn9WWK4V4fiTK+Q4LX9OhIYE1gsEjUT0mtFr6KWgi0SDlvYVLhUiDYs3yq+KdHhB4E1GRMd+vfl/Og6BeT1DxyTwIzGC4Re1VoEIB23wlZkfxG4TXcyxazvdYpSXFI0XEjYXNesKO7AqSlGgFW1Pi/Cu+GUSH1mYI+DsCoE/J4YE2QJyV6+TVSfDTX6CmzOufHj05InD7squaD/ECHkWUblal942ZMwbb417cUD3i6sLyJr+IQzXSlVrZWXVqmo2F6BTVVv0evLlyW+MGtC5USWLtKAJq9LqtL3jyZfefOvVYQ93bVIVhSmKQPpS6ZI+z70+ecwDrUlPE4KGrhVacOMmZ17W5+mXJr/16nP3dbwgPWxWQBhbSt1r739xwpTXXvhfh6ykkBOccLIzvVHnx0a98dbLT9xySXUphmIvFV9eu/vg7vWT68C5+6YvGklblaX9ylkeT56V3OqhWTmmE8GrX+ngMl0TTkPIGL98+4EDOStezzSj0uq5FYHDxad+eqappZW0NgPn7g62kr9yRLuQtyyh6o8sVfgVS+8qj9DEsNCS2zJu+dDU5yPfPt4EhYgM0mq122ceCFy1/5NbK1kZl/xct/+C48YFytrxVxV2etaDeigsieZ9BLqBe2jSVvIHKiJ+19ySGVzqOfMoPeTt9/ngL1RC8L1rKj0YCi1Ux+bW2HPBha3SyMOQC5Umh/VDAplDA4LyI+nOuVB8RvFDJ8hfyER68nWrE5ZIkBtXsfSy5BLS03ktiUDwhULrRin3rgw+zQdZivG+l2rZsCUg3bmcpmr2sT6RqxZ3QZbRo7vWQa423mlIM/lOuejQulGPo7KsyF78EKr/OSSc5UlbNX8B3nN5YEQCqjFDIR/6lWBSV1X2KXhLMGtcKLQSGqHkQ/0jrzqKXyag+j9jPdAMeYo/H5/IMri84df05VlbUfGfDU3TjyD7gIwL/IGe+vH+DiPDcK0HNZlHTGyf+WlwRnzttZZZIKLyb+vYR6sVsqsUnx/Lz7lN+o3nTfIgv2p0WoOhR65fyKHtfpIm/sU3V/0dKywDEkvZqufj3aa88p8Su4o3rvN0/QSFPLwl0+hBOGhfwCqdQHiY8QYqrMIFChsA8CQ1g48ahblTFmCfMQA9UMNC8eJVpixfEroL4wLduIQA6sNHNvGklSZoPejyjYRhTYlO6I9yAT5hTSdfYRG/TKdvlT6yAOORgTPXLjTJuEKR/TK9xC+PKQzaHiexBgmMJy+j2Z0objxXYT6eHxhPFa9CAdEIj6uqKvN0ytiL3zCuCQftcPaJgl80TN93ABW4iKW+VYF/T3aneBDjTWOwk+dDnkrZqM5YgEcGWEhCrU9DXieWUFOjHClDyVla3yAIrRtlb8N+nqqdPFCWVd7nfJx7WRAWQfwG++jdqspeOc3LIiu4P2/TjfpAbmTduIImcQybIT0MtDrkgYaWYcC6aiSk9+NbjZl6AU3GotpYAHKzK434y40BWgm1zGfvjbSz4bsFP+8DHLVTBrStaSFONVifTtd4csbj1XgrAkr9DufzRKOM6TWazlnXLdBKqOpvRu5A43maZmC7sqrBkRIayy8jsG1bNH+Vj3OWH+c2ptiKYuJaNgzynD0/zF/8j0YLgMQGLeCk0VsZ4/PqPypeb4wny0fL1eD9nw28qf3lHe+Z5cds1H48hL/cGKB1ozdYAk8FL2ydkpSUUrn9WLJ+53Xm0GZjheK6e/ojna9o1/H+eZi3ohIWcvFWemIf6yHMr9xjGqvBybL/BKF1M1WXAeJbOmHo8A+3YyPVfj4ezKGVUNs8NlwV//yf1OTklKzhXpausQC/SUfhQbeept1QcE6v8klJyeWbDVxJsBgbk0Awcjb7v+nRqN4Vk70Gtrp2Hb8/FdLMnJ7/3/LGndccYR1Q8HdRZK0VWqI0/Umzp8t4dVXjQan35GypyZ2QWadBIfi8c4rxZc98ymnkkTOMgSTT9GI0z6L80RXVqlz66inMK2qYoHWhqw5zVtPxF03onYl991Dugf7s5ZvOLrSIvWw//tDI+tT5NHu+WlAfLvKg12j+RlU7fZXRL6nDohNdojv3TdCS9g7dygeUxxP7BgqFCOhtfGTmpYgaS2ASutG9DFoN70yMFVoRVdlLofXhQYbGQN5LYobRnZSZ+OC0poFWiGo5mKVpU/FqbiqiFhxIDRf0Z3c1X8FqJZugJS/xTc7cMn4VGSZzs+08/asf30nnmhtdeZyOX8Y/p/IuedAwNjQZP0guIubE50ROwT1z0wRuipF/gpp6YdCSB23PRpIkCJIHDeCpPDW8mdnLAqo08HLIGx/UgZIO8BvzanIruVBoJZS1n97kw48EBZV5sa496BJz8kkRZZ7WWUHZfelM8KHnONPqeDRKJP0hbzntW5pl0wSthJpuZdf58RcegTeRiLp6GRvJ+Es3g3EKq5Qi4+uNjghC+UNcAHwtUhwXcGhnpwRSdRUeEBSUtSo+2MoYruD+y8ghdrxpkO1tEVWL2TVYb8KEbSzQZjJo/XhJOgpUsrA6EaytVFjJMm7hI7V4K0uMJWV7CncLeFDaYipXzdDewThZxbmdUGA3OYGgpLK7/61EASrHsgD78a81Te6UWbza154UagR/TaFV8MErkNsdVIhigpY8RjsdLHAjokfZK9d1by+OtxAo3kcmF03mM4unVMQtY+VaAZIlU1ZX8KcXQM0Re//EYCsCrciQ/i3NqKvjozwNZ4WjmEvfUYH+elCdtQwMDi25mSVpJQ3NNxVOdKHevB6PhtuSDrtRh4N8Gr2ZmJgAsYBujzvJ9TyfGWoDcLKgaayCuIzX/AeqX8a2fxqA1ofnJJpeW3PMChNo2rOWnH6i2+Ny8cnwrgFtdqxcS4a2kNdXUfCGZxrD/AjXT4mMj7eS8hWH9thFTFq3MhK8qy2DjJMAKRhNJoOAqv7EKmNDze7gAIhRedxYWO4hz/Ogh1UoSkaMjrvNHehuzIyrSRseNFRTuRg5PBlWsigpvsNC+2maCdoqO+jDSc/eDApF7m1EYmqVatVqVPmUtQ9cGyu0bvSAyjVVouVvnXF7WmiWXKMVKa1q9epVshZxgcCSrEroFmNG7zGxAkTP+C3QNtjL53Rud6v6uc5YoqCetBuNo4u/puCx13S/iVO3G8awRlTck1zkQhcfwBrPBooPLXqsbky5iE3QzipnstPTlrARgdJj9Ay+zew+fPr3qzdv3bZt+7ZTPA16EbiWSIStRop2sO7y1r1Uzya1oJV6vUZ9sngNtLJtu5drhgxaF0vSyWp1Bp3BdmhF1MKoTL37Ekv+djTPUKzfJpLWhWZgVv9I9x7PNejEcb7Yqbg3NOpG07HCFGLI86zkfHRlDMVfTdDONEOb9Bmbh2qwbqOA0u774ZDXYo+xP7FDS/65AVM+Mcpp4MMTq5raJepI1UeXHcnHtlaC0I5kT5Txh8FXErKBI6KrwWyHrvyTaUZBQu8bPfqM7it8y8SoNQ+w0bDK4gJFVH0HXcioyQwehLx5rQpD1gztZ2ZoPe+wVQCqjXLF1nVPDjMWIRcekF50roWLHjCqPIIZC4JuT0+TJEp67AD1k9haCUI73oD29ajQdjUUhL8rWqGdYPRoLmySJC02VCHNQizmRwnEqmTv51Y+XAtmqX9EYQnzIkHresOA9hvOtWkfs+It5DMoj64oSrGgJW30yIEM7Zoe7OcjvA0BVf+GelxYK5Q0G7RTDGhfiwptN6aNqXhDecEC7StGj74ApS9tqQGt0Z6ZVHyNMbQLf9KgZglnCSjo82Eh25uRoE2YZgiEL5h1455FyzjpVNoUXyDQDzOm7APHM3drkcvlHtyHkL4Is7pxiq2VILSTDGjfiQrtTQa0m6tZuXay0aMZsE1GrGbFcCyEoZ+S+H3EKBu8QYVa6xo2luHxMfoQbLK23DwDWlptVEJDqNkIXcLH/lq24PMZn32aw4tOFBFa6FCzcWugLA7XMGS8oRJVe9EYyFnLWjm8bun8z2fMnLUPaxauHRvkumjQXmcIhJwG1mXsU+P+N8gyJroXMq7V8KLXp06x0FtvTXk+GE0liqjSoB9zeSF7eot8VVRsTdB+nmqCtuIGQ/maQPQ6ooz9q3OPwZFJnbOYdfN20fVa3k0y+Iy7Z+3FXK/SFe1J2kqDApn7qva/3Kk2m3BfGnotV76eNNr4PTgKAu0kG7StWd1qDR9sb1a+BLSMaQgyfhpJ5L4vySugdu5NYfExLbDkKUldJ/+F2XQwLUOFQzs9VQiuJg1l5tvUlEFk0EQdZXVVNf3gDYgdJHJLHxh6bVGh5dVf2ow6yGqXkMn1NR3nk+xlaTinDaL7224hfb4FWsgYzPXaoxWCA3cTk8EK7UXHdaZ85d9jMRmS9xsOu/9Sa+xtplb58SCU6HHbyFoDBaqIogYP/wnaLXUC76kbTQULQOvHy8oFZpiI+rIB6ZiYv24yoE+pE4P0oD9yeaAUFvlsWnG5ln4FNm475iAgX/9Ba4V8ZxhB3VGCW6LxFOWs0IqoPVvWyFu/NrgrJ7g+ZWUmAyZDrfXMVlXxRBPXSqi9j00UXb+QXOWBHSadctbrMUQWiGCG1X6PyRoNH+8azRke9HzJxCYPuHOEZcbCeaQOGQ4tUgmSS8utFdyZLRa0pjgdlwtdvoe2Qyv3uJG4GTNO25cQuCz1Gwu0AsrIM9T5dwIaNywFVI0NQltuFpsRCv7NpH15yCrG7ayNKfT325lnzY+XRzm6Y/IfSW6U/h17jbplQkSClknyIchwD3cOOBWhYBJ58lruZfu7hnGnC71XPK4NgitJLlbTVMFbmpOuJO7irfwRlGGJX1mgJe2uYX3T8eHaXOUW0d2YiwnD8yWip8GpAJ/o/VBiYLT1DjB54MfjoB8u1DiHvU6/pbI1HY5oVlyDP7rRQ9RfoesF/WOAljE4HkpHLqDMHYF9kzHkEtJ3Vv9T0f/l75YwSvN9xdEQLmoSRFcSE2dxaP9qQNpJ2MnmBt7Je0wavjJXN2sIpJGJgU2GOSAK4FH3aWzRNTsVO/oVvl5B6RpazU+CRVFlJaXwFYieFUQ/BLxa1Ym8Z85puBgFDHAB1bg0wWgKbnmUVuPQ8KlesUDLsZ1el/TLfekGXi+MvN2LoQEJLWGfyLAPSYh8dtleDn8RoBVR+Z148oUwsUXyEBG13csFwk+p8Iz1xhLVAblE2kqnXGMPJABtRw4j+ftBFSiCVPNNTLfkrVxbaRGv9OLHv13ER1v1I8wsFR9exCpxetBAVuCTYLsww8yfSU2fX9YLfhFgpVkI9Vh5hXhDIOBDraOpCAGuZUY9Pv7+oKdmKUbZRIX7QNzoXfa2Vbwrm95Xrt/pQJW62KF1o3bHiAE+5aoq9G27WyxlHAj6PwRUzDGWsQ0X0FYqDJKx1RojlLbRcMFreNe4Bx995zDthWZxhZMxP4T5hr6CD4+5sn6deq2HbMfMOUimf2feZ6HC9sAM3fHQBZUSJcmTUjnr2qE/kbe1pBwdRPkV5MXN71mT7tiJmZPYg4m4TogWsWgWCGAEsZAJlZdl9FN/JVzVS+WbT/jI6M6XdXz4R/C4aiwUoCjQ/ieXRjv8Oemxvn0GfngcbAM6tbqR7yR0f2Cu733mxsuvG7gcsxgJM7Qi+l9wr5yZawrlCmwJ8RBR+mJcwK4D8/T4btg3ZcgSu2Sqm3OnCz1mOGjAGlo8bfxrU2f+cghQyNdXlqeDqPI7hhLYO6Y/1a/PA+O3ci+YQkztaLauWSDAmCGiy89+18kIpiM+R5J3Gu9WpwEVcLFhlkSDdpgN2o7HCX/5DStWY1Pbj+eD11ZANY8pqjFK2opfZ+CboBVQxVUGtlj1+WnsGeH73HwL15J/rz7J1WYyKkBP8Sks3sOLVwfLW7nQAh4wglU5EJok+2XyxlZxaFeRYcuBAECF+9L314q6iWPi2lO0KjV7Mg+E2JQRCDG4mxr30L5PVhW/XyejyWd1YoLQzjagvT0817pQu38pc8kQjuf3saJePryvGfPmokHYyycxtOKTwUzyylaBIKFrvLoPBypeAzMW4G+GwMaOOXrGA/FLPsxjD1RFYd5srObjbc1M/n2U+SeLnoHveEAdnb2y/msaHVb530CWk1dDY/KYz4EgfU90n63JZJg9gnIJ5j0mPdiVbQqnewf7OPJQDRjCw5YOwCxOrYWxNzYD84OkvQxon7fEfJFZ+i8u0Pjb47PZj49cx0YqoMS52GtpRcVzn2YRHMEqeeQ9y1T94UGQUC9xUeqNeQCtZjr+7EZ35VGT30waufGXJuaZLKIGS1kZVuuFSh6eBVobsXC/xl7V4Dn2Lv0YP1OIN9xk6H6UcG8eVpmzT1NId1dZTtElvQn+KJVGhGngmJpd6TKcB6FUuLXBtfNwvkI+KMB3GdCOpZ8o+fgl7vh8jO4vQG0Z8B6qEE75W3bQ215xBm2FCiQNvnxX6olPy7JfP9Ys4JYU0O0nwQdFr6KPGJGG+nv9PsWfj02VqyR02TIaoMWa0zUaRFYwKt0qIyVU9aUCAqWsUO8wLXpDK9kfuYoOzIWu2A28pLJ62BqdAPv7FLala4J2dhq69IfgW8sdXtV8s4DE2zaZXuqWvinoSj4dGxhcO9oQKO3ZrRK607j+bq4PC+1nerGZNg2oHHz9Ikq4b6fpy9X/TUS92Y+Hq5vscNR6vumqJR3Jh1cfoz/Lt5jmuogq9ltlZcbcqdmCXWUizbd5N9fGtf5fhjQMtFf/5X2WL4+Ob1RoVLjZqUg0veQus/fKuq4c/H6gfc+K/FKpx/RNp8lb9e2Y1asSzJT/DH91/KtPtw1ck9jpyZfHvzb6oUuCu9PtHhv72mtjB14RHI07q9/0dcdAgfUd+HncdRWt8fYIVbtt5lY4NZ2/9eNuRNYJSV1Hjhv/6uAWVtvI1WHKRtIX7N38XqdEGnFx6VPjxo97/hrb8QqUetkL3+2AXuvy4dXT7syUwkQQgOpeu/fUlQd8VM7nbvnulV4NkszNoYpdJ/x6wA87D8fWvn9HLVR44RarKxy4J7lRdnaDNP5AC1ENN6N5qxZ1odXiltigt0kVG7XMviSLqu3WB9Hf3JkXt7qkdkKYPpifImY0a9WitjvKVcbDEzMaZ2e3qJ8uokgXM0MrtU5zct0F/OSF6SUxI61cvUuyWzasGLwhKtl3GQKPCxt4EyhKIxinWURI2mO6QBJt55HYJ5ZzAeZzO+GqFIZvxd4fU4EcfjVrO+Rx5ticKMV0BPOtQsiF5q9jK60YZgMn9LG2JkqkmH305wgxZVmK7Sp2pRjLYS8h+nU0wC/m2Rppb8yhuMmBttTIgbbUyIG21MiBttTI2MCxxyE4FDd5UM9cTSW2c4EDbQkTgZZ5mhQ814G2RElEGXMPHD15Knd/Tl8H2ZIlAmeTG2/pffNVpZsd5rykQIhkbIcfHCoCCS63x+MpnerYDjnkkEMOOeSQQw455JBDDjnkkEMOOXTm6P8Af29k4A0KZW5kc3RyZWFtCmVuZG9iago1OCAwIG9iago8PAovVHlwZSAvRm9udAovU3VidHlwZSAvVHlwZTAKL0Jhc2VGb250IC9BQUFBQUErQ3JpbXNvblByby1SZWd1bGFyCi9FbmNvZGluZyAvSWRlbnRpdHktSAovRGVzY2VuZGFudEZvbnRzIFs1OSAwIFJdCi9Ub1VuaWNvZGUgNjAgMCBSCj4+CmVuZG9iago1OSAwIG9iago8PAovVHlwZSAvRm9udAovRm9udERlc2NyaXB0b3IgNjEgMCBSCi9CYXNlRm9udCAvQUFBQUFBK0NyaW1zb25Qcm8tUmVndWxhcgovU3VidHlwZSAvQ0lERm9udFR5cGUyCi9DSURUb0dJRE1hcCAvSWRlbnRpdHkKL0NJRFN5c3RlbUluZm8gNjIgMCBSCi9XIFswIFs1MDAgNTY4LjM1OTM4XQogMzAgWzU4OS44NDM3NV0KIDY5IFs2MzIuODEyNV0KIDc2IFs2NTYuMjVdCiA4MSBbMzAyLjczNDM4XQoyMTUgWzkxOC45NDUzMV0KIDIzNyBbNDYyLjg5MDYzXQogMjY1IFs1MTMuNjcxODggNDE1LjAzOTA2XQogMjczIFs1MjYuMzY3MTldCiAyODAgWzQzOS40NTMxM10KMzA1IFs0ODMuMzk4NDRdCiAzMTcgWzI2MS43MTg3NV0KIDM0MCBbMjYyLjY5NTMxXQogMzQ5IFs4MDMuNzEwOTQgMCA1MzcuMTA5MzhdCiAzNjIgWzQ5Ni4wOTM3NV0KMzk3IFs1MjQuNDE0MDYgMCAwIDM1NS40Njg3NV0KIDQyMCBbMzMxLjA1NDY5XQogNDI4IFs1MzAuMjczNDRdCiA0NTIgWzczNS4zNTE1Nl0KIDQ1OCBbNDYwLjkzNzVdCjU4MiBbMjU5Ljc2NTYzXQogNjI1IFsxODcuNV0KXQovRFcgMAo+PgplbmRvYmoKNjAgMCBvYmoKPDwKL0xlbmd0aCAzNTMKL0ZpbHRlciAvRmxhdGVEZWNvZGUKPj4Kc3RyZWFtDQp4nF2S3WqEMBCF732KXLYXi0lWzS6IILoLXvSH2j6Aq+NWqDFE98K3b5zJbqEBhY85ZziZSVhUZaWHhYXvdmprWFg/6M7CPN1sC+wC10EHQrJuaBdP+G/HxgShM9frvMBY6X4K0pSx8MNV58Wu7Cnvpgs8B+Gb7cAO+sqevoracX0z5gdG0AvjQZaxDnrX6aUxr80ILETbrupcfVjWnfP8KT5XA0wiC0rTTh3MpmnBNvoKQcrdyVh6dicLQHf/6nJPtkvffjcW5cLJOY9EtpE4Ee2RophIERVEB6TY+45IpUKKSXkqkRLsKQQpk4joQBQj7X1NEXkf9hRxRFQQ+VpJdCY6ISU50RnpQErFkY6cSCLl1FNRlpxupChL4WuUpaCeCrPIKEGSeCOpKLXkOGI/S3Gf7H0Tgh83meA+nfRqqm+72d7QY/HtzVq3c3xouOxtzYOGx1s0k9lc2/cL9Ma5Qw0KZW5kc3RyZWFtCmVuZG9iago2MSAwIG9iago8PAovVHlwZSAvRm9udERlc2NyaXB0b3IKL0ZvbnROYW1lIC9BQUFBQUErQ3JpbXNvblByby1SZWd1bGFyCi9GbGFncyA0Ci9Bc2NlbnQgODk2LjQ4NDM4Ci9EZXNjZW50IC0yMTQuODQzNzUKL1N0ZW1WIDEzNy42OTUzMTMKL0NhcEhlaWdodCA1NzMuMjQyMTkKL0l0YWxpY0FuZ2xlIDAKL0ZvbnRCQm94IFstMTA0LjQ5MjE4OCAtMjc2LjM2NzE5IDExMzEuODM1OTQgOTYwLjkzNzVdCi9Gb250RmlsZTIgNjMgMCBSCj4+CmVuZG9iago2MiAwIG9iago8PAovUmVnaXN0cnkgKEFkb2JlKQovT3JkZXJpbmcgKElkZW50aXR5KQovU3VwcGxlbWVudCAwCj4+CmVuZG9iago2MyAwIG9iago8PAovTGVuZ3RoIDMyMTEKL0xlbmd0aDEgODkxMgovRmlsdGVyIC9GbGF0ZURlY29kZQo+PgpzdHJlYW0NCnic7VkJcFvVFX2LLMmLFmuXJWvX/5atxdbiL9uybFleEid27NhxSBonEcGJHbwRO4RAoeyknQbaAdLSdKBQ2oEWGIaBNNAMk7KUgbKUbmGAaadTSqdrhjIBOk2s3vclr8RAKKFlyLv5+W/799xz3333vy8jjBBSoCsRRT1r+kLhjT1Tv0IIPw+9W/v6U/1v3P+8Edr7oN26bSwzqXlK81eEiB/ah3ZkpibhrobrDbjkO0b3bleMlP4CIcPXECpJDg9lLrC8XHEAnu+B8dph6JA9IimDNnveMzw2fUmMUClCxZvgCo9ObMtUBrkXECooQUjaPZa5ZJIKksdh7t/gcoxnxoaCuv5ewAc8wk1OTE1n70Bh0FfCxid3DU0OS796HdRfh0t2GGeve1CyH4YRzmaRCu6IcpLVSIbGUQFrLSgS8ADNVbPfZjpPU9jzB7IemPzd7K2nfie5YYkORKbEHoyuufaZf3VvUSVOyKlEHHml8Mil4v0W/vfZW2f+KLmBvgJNKSJzujGSiy2d+L8HkT07hqeZupHpzCgugnEJ+FpExBSDh8FeaOHCWduQhLD+ArDjW2Q7tLtyd7wd+GTfz2W+tE+syKCjyIH25vjRf2DegfDN4sR7ySrmXdE7RERlNorYcJegu+BuBcsoKkFOlEJptBKtR0NoBxpBk2gX2o32oL3ZrKiDjXbAaEYcHYXR6dnR7NHsazDnSrieQywGbXB14V7AsYpGlok4SNSDEJf3+EWkHbWh1agX/R0X4iJcik24Hw/iLXgn3o/vxveJ04rRV5jFEuarh9Bf8nWMDICUqxOkRD/N1ylqRtfn6xJA2pqvF4AN7fm6FFbIlauDI0pAU65O5/XAyhTBSK7Oagg8Mw3cR4H7NrQWTaAxaI2L3hoBjwzDaBp8MgL9UzA6jnqgNYECMJf5czc8mYGeAWjtghkj4hwHqkFBVA0SXvK0I/+8Y8nz8/MbgM8EWgG9Dcsgt6FLwKpdMGP1nI2LtZ0eMw3XJNorjuWecgBeNWDHodYPPUNwX87e3H0nzNkmPpkCtGl4ZkLk7UAVosZpQJhC9SgEwuKJzdiNzgd220TfhkR242J/BkamQN849J6OqS+/Feo+tkx8ovLIQsHWOVlxTubk8jOQlz6eEC3pWCRfXyRPn6nQ6mUkQbedgdy4VCQEZPVp5bJPRJ5jUiD7iBJcIlNnKPcskNc/nyKVn5PPsNjFw1IETidLzohnv5BNKPppY37UQvahyLJj34E395KCa+F9fa6cK0sKvR++4s5Cwa/CSfhTLESJCL537vT5/nELnHWXKfgJVHl2rFqAcRy+6c5kPnwJseus2KIQf2v4wEIFZGZ3wiHTR9Z7cnn/f9qFmJFxto5Hc1w+qYL7kOYDse0f7t//ppC3kOR0/fiV7MmziXuu/H8VXATf5Z+VcvR/bcDnqBxH7NAM52XSTgaRlr15pnhBK2iNMjcv8DwVqExmlPExgyESrhX0HOd2SSmpebH+1TB9jjQ2FI8Zh4tjjcSqbakOpTWutN2W4pRE6j51TMlxylvsWK2Y+YPtViX3aAwTgmMYs99do9l3STPpRy6E2lwcF4smSSRsMAKSiCDV63KAglEmleLJ9TcN+Ndd2u3b5JEFbNpk+aotgYahRnvM5A9a3YOF6evOb5pYV61WfVmyRaFIjabWXZxQKjcXXFFqAawIYF0AWKEPwZLFohzPCxGjTKeDPiMAX7zx5oHAusvWVA66pP5ybbOlKxNsHE5Z2ywmQlrJk8RPMD9WmL4W8AcA/xrJBmUJw9+TUOviI86woriCKyngLO7qsrJyRNlpm0yRVciCBNSGUIYXkiQGuHlgJdEza8A257IjdNFa4NtII6EYU7gdo0kiliQ99ROog6sx1H89P6NL2y0IqzSG9nj9Ck4pcSarj4STTspWijqT4SPVSaeENQo8Sf+RQJN36QhWN7BFbAB17Pds8CiWi2xY1Cxjbw3gipY0kgWWLI8B8SjLnqL3gN5ipjlF3VRUqXVrtXM18U7xnx6qejlMnqSRu/V33PtSmPyMNt6lu72DHqaRY/jwTBspA+2KmVX4e6dOzNUfZoin3mSR35B9Dz+NDyE/rAdaL0YHBB2jAb6VyaRitAgQLTIICKMegtHt4vmIVMrDCsRkYvA8VZF0V0W+aQvbzRpCPGFbtWBZuRETSptrlCa5vbBY5WwsMPo0kyZ9QO4IW5z+0kjE7DPp7ZVyvanUZTdIuprv0XgLS+waAOC93ga9YcQmLdOZfWAjARvfJIeQAwUQ2lMbjYKbgyQGfjYqicxYWwvRbNDrmGmcAGbVirbrDYY1zO+dZL+WrRk1dfrDfdH0ZGvVugMNXZisidvq9PqwxRUNW+9zd6+MFRU6fMrK/vFe7Kqs+UKqY6xRZ9/Q19Nlsb6tLIXV9oEdd4KvnHOemkUGYJ43cqI3WGjC1nk3vjnesD3lT9h1mlKDJuKp6KzubeQEs8U6II9k0qnhpMGjU+tLNJGiQmdvc8+A1W6MRtiaVGRPQAwfQh5UAzsWspDIbG7fAvcQYRD63JqIKyGuF6DjL6kwLW92122MeJp6qiwNOhZ63eRmWBlcgJv/bY2UaevLmzrWFCtSuNJVO9gYO6/JpVRp6ptqCpVOnzI53fRmZKVK7eTMjmMu62Bnz3rgXgnc78A/YvlqlrsRqOudsQhLG2IamSf/Xv3mWvjXfd7MC28VR4LWqKO32SOUmYF6NNPSMVyH8dBmjV+hr2typiMlazdZHCJ3CXJmrfi3+BE4HddBflgporGQNM76FsBCZGGf0ZhbfLp4SViA5gyDOV6IlT9vGq1NcE5Pc11zb3XdhSpPNBpUaDVm41VtKxLb47G+YPXaSKQnFOr1+6pjVb6ogPV7+NvfSIRd9Ta5Llxe4Y/7XU5JoYS3WqI6nUJfpNRShSweDXZW4a1ca2V1Z1VFR8DfUVmRCNelm6LR9LPyCjXKZsVvkxPkoJTDSajJqDe7ESHxb0HQjx9m5++5/MHzMZGZSE1mIWnIHBKavlFFKSVp4lVKdH6+pbJVo3R6lfZExRXBhFzpZdrYSfptiJuyeW1z2yQXKzIrSREMu4J0kpu0rEKhw6ssDqwWLvf2rIjIi2ALVPVtX3FnwxYl00rY9wAth6iPoJ5ZvYKY5cDMuc1nFLW7xVE+nzxyBObzOOvj8/NzYw6SBFOAHmm+vrSA2ls87pYqTGmCPkkFZp3Fb7YJekog3+6kEDTEFjC664xa9xp/ZWsFJUniUckMlZ5uvZ8vAX+oazHv4robd3rqilUej0pu4izjVVGTzXEgON8z5o+aXG5vdaBide1F4kzmPfh2IyrgGV7AcjFJ/QKSsUUk7TkiBVTk4W6t8KZ8lCbps6Qeuu1BkzMOLJIUrDVVurqcLWzx1DHMubxd9ROe+qJZ00YDMaPDdiAUZ0YRMeP8EmxSofLZd/eiAJ+PcAPGqUxtw1AiuSka31LjCls76mtT7qQ8PpRqvSAubGtp2pEI+VaGBi7csCo+UM1W1pj14OOg3ct+u1vPC9GFpCOL0iqf46kFSEivs/m1XKRN8rStaV5YV5PYkTJF9BSvJSpfwo2xq55zxAza2OseVYHJF/e+a2sSyQser7C1MT3SWChfxcUUCg5L+c4obKFy6z9V7G/OEHd4A+wNfpn1yKdd2Coyo42wSKNJFjPMGqWE2hqtRrvTrHGqNBqXipmJ10O0FJgDjm5nStw8/bjeZzIYy9RKaYnfPmiOBYoV7O2rAa9vIAVwGoR9OSTyjwnumBCRyXIZjsYierxB2+JJrKHtV2kJDviMvPqZHyed3s7O4/rdU+9Ew1ol9oTDbFdCNpcCDzj5DMELdDadL9zqebWx2W0llepYsOFnmq5m2bzRnd5ISes+lsLrA5a4Hsis3A+cCtrVToeiCfucfX0DlloL86u9nRtPxqyuaUMVr2QsrVVV1g4hDbwk2ZPkLfwARBOcKtryJwlZ/iThnGsbKX7vtgg5TKLT5j1RcpCEfjjz+F0h8iiJfNF2reUbEnjHQLjO/BzjGrFy1XxHfXLmELyvT4pZ/AEkY389X5/XDEdqKstxZ2cMmSAA9GsPhugTJLnvRRr6QY+hxmFymMyDwYniq5NkHmcb/H/w+0HOpFWVya3h32gYMIvg9uw76CnyGCpi0bKHcrmYBZjFW2WXkyhNarVJSZxajbW01KrRlKs9h/BjZkdpqcM8035UbS3VWNRqi6bMzXLBceLFI+QgnL9QSjQ3F284UObxlJW5XMTrMpvcbpMZXofoP5F+JXQNCmVuZHN0cmVhbQplbmRvYmoKeHJlZgowIDY0CjAwMDAwMDAwMDAgNjU1MzUgZg0KMDAwMDAwMDAxNSAwMDAwMCBuDQowMDAwMDAwNDE5IDAwMDAwIG4NCjAwMDAwMDA0NzYgMDAwMDAgbg0KMDAwMDAwMDU4NCAwMDAwMCBuDQowMDAwMDAwNjM0IDAwMDAwIG4NCjAwMDAwMDAxNTIgMDAwMDAgbg0KMDAwMDAwMDY3NyAwMDAwMCBuDQowMDAwMDAwOTYwIDAwMDAwIG4NCjAwMDAwMDEwNTcgMDAwMDAgbg0KMDAwMDAwMTE2MCAwMDAwMCBuDQowMDAwMDAxOTE2IDAwMDAwIG4NCjAwMDAwMDIwNDEgMDAwMDAgbg0KMDAwMDAwMzA5NCAwMDAwMCBuDQowMDAwMDAzMTg2IDAwMDAwIG4NCjAwMDAwMDMyODEgMDAwMDAgbg0KMDAwMDAwMzM3NiAwMDAwMCBuDQowMDAwMDAzNDcxIDAwMDAwIG4NCjAwMDAwMDM1NjYgMDAwMDAgbg0KMDAwMDAwMzY2MSAwMDAwMCBuDQowMDAwMDAzNzU2IDAwMDAwIG4NCjAwMDAwMDM4NDQgMDAwMDAgbg0KMDAwMDAwMzkzMyAwMDAwMCBuDQowMDAwMDA0MDIyIDAwMDAwIG4NCjAwMDAwMDQxMTEgMDAwMDAgbg0KMDAwMDAwNDIwMCAwMDAwMCBuDQowMDAwMDA0Mjg5IDAwMDAwIG4NCjAwMDAwMDQzNzggMDAwMDAgbg0KMDAwMDAwNDQ5NSAwMDAwMCBuDQowMDAwMDA0NTg0IDAwMDAwIG4NCjAwMDAwMDQ2NzMgMDAwMDAgbg0KMDAwMDAwNDc2MiAwMDAwMCBuDQowMDAwMDA0ODUxIDAwMDAwIG4NCjAwMDAwMDQ5NDAgMDAwMDAgbg0KMDAwMDAwNTAyNyAwMDAwMCBuDQowMDAwMDA1MTE2IDAwMDAwIG4NCjAwMDAwMDUyMDUgMDAwMDAgbg0KMDAwMDAwNTI5MiAwMDAwMCBuDQowMDAwMDA1MzgxIDAwMDAwIG4NCjAwMDAwMDU0NzcgMDAwMDAgbg0KMDAwMDAwNTU3MSAwMDAwMCBuDQowMDAwMDA1NjU4IDAwMDAwIG4NCjAwMDAwMDU3NDcgMDAwMDAgbg0KMDAwMDAwNTgzNiAwMDAwMCBuDQowMDAwMDA1OTI1IDAwMDAwIG4NCjAwMDAwMDYwMTIgMDAwMDAgbg0KMDAwMDAwNjA1NiAwMDAwMCBuDQowMDAwMDM2NDMyIDAwMDAwIG4NCjAwMDAwMzY0NjUgMDAwMDAgbg0KMDAwMDAzNjUxNiAwMDAwMCBuDQowMDAwMDM2NTY3IDAwMDAwIG4NCjAwMDAwMzY2MTggMDAwMDAgbg0KMDAwMDAzNjY2OSAwMDAwMCBuDQowMDAwMDM2NzIwIDAwMDAwIG4NCjAwMDAwMzY3NzEgMDAwMDAgbg0KMDAwMDAzNjgyMiAwMDAwMCBuDQowMDAwMDM2ODYyIDAwMDAwIG4NCjAwMDAwMzY5NDEgMDAwMDAgbg0KMDAwMDA0OTMxNiAwMDAwMCBuDQowMDAwMDQ5NDY5IDAwMDAwIG4NCjAwMDAwNTAwMzcgMDAwMDAgbg0KMDAwMDA1MDQ2NSAwMDAwMCBuDQowMDAwMDUwNzIwIDAwMDAwIG4NCjAwMDAwNTA3OTUgMDAwMDAgbg0KdHJhaWxlcgo8PAovUm9vdCAxIDAgUgovSW5mbyA2IDAgUgovSUQgWzwwQ0M3NzdBRDZENEFBMThFRkFGQ0ExODQ3QjI1QkMxQz4gPDBDQzc3N0FENkQ0QUExOEVGQUZDQTE4NDdCMjVCQzFDPl0KL1NpemUgNjQKPj4Kc3RhcnR4cmVmCjU0MDk2CiUlRU9GCg==', }; diff --git a/src/components/CollapsibleDropdown/CollapsibleDropdown.test.tsx b/src/components/CollapsibleDropdown/CollapsibleDropdown.spec.tsx similarity index 87% rename from src/components/CollapsibleDropdown/CollapsibleDropdown.test.tsx rename to src/components/CollapsibleDropdown/CollapsibleDropdown.spec.tsx index efee248ffb..b288fb9de5 100644 --- a/src/components/CollapsibleDropdown/CollapsibleDropdown.test.tsx +++ b/src/components/CollapsibleDropdown/CollapsibleDropdown.spec.tsx @@ -8,21 +8,33 @@ import { store } from 'state/store'; import { Provider } from 'react-redux'; import { I18nextProvider } from 'react-i18next'; import i18nForTest from 'utils/i18nForTest'; +import { describe, expect, test, vi, afterEach } from 'vitest'; +import type { Location } from '@remix-run/router'; -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useLocation: () => ({ - pathname: '/orgstore', - state: {}, - key: '', - search: '', - hash: '', - }), -})); +afterEach(() => { + vi.resetModules(); +}); + +const currentLocation: Location = { + pathname: '/orgstore', + state: {}, + key: '', + search: '', + hash: '', +}; + +vi.mock('react-router-dom', async (importOriginal) => { + const mod = (await importOriginal()) as object; + + return { + ...mod, + useLocation: () => currentLocation, + }; +}); const props: InterfaceCollapsibleDropdown = { showDropdown: true, - setShowDropdown: jest.fn(), + setShowDropdown: vi.fn(), target: { name: 'DropDown Category', url: undefined, diff --git a/src/components/ContriStats/ContriStats.module.css b/src/components/ContriStats/ContriStats.module.css deleted file mode 100644 index 7d6c83ea8e..0000000000 --- a/src/components/ContriStats/ContriStats.module.css +++ /dev/null @@ -1,7 +0,0 @@ -.fonts { - color: #707070; -} - -.fonts > span { - font-weight: 600; -} diff --git a/src/components/ContriStats/ContriStats.test.tsx b/src/components/ContriStats/ContriStats.spec.tsx similarity index 96% rename from src/components/ContriStats/ContriStats.test.tsx rename to src/components/ContriStats/ContriStats.spec.tsx index 8edb853684..4a9f1fc94f 100644 --- a/src/components/ContriStats/ContriStats.test.tsx +++ b/src/components/ContriStats/ContriStats.spec.tsx @@ -6,6 +6,7 @@ import { ApolloClient, ApolloProvider, InMemoryCache } from '@apollo/client'; import type { NormalizedCacheObject } from '@apollo/client'; import i18nForTest from 'utils/i18nForTest'; import { BACKEND_URL } from 'Constant/constant'; +import { describe, test, expect } from 'vitest'; const client: ApolloClient = new ApolloClient({ cache: new InMemoryCache(), diff --git a/src/components/ContriStats/ContriStats.tsx b/src/components/ContriStats/ContriStats.tsx index a2db307d91..91e6b9872f 100644 --- a/src/components/ContriStats/ContriStats.tsx +++ b/src/components/ContriStats/ContriStats.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; -import styles from './ContriStats.module.css'; +import styles from '../../style/app.module.css'; interface InterfaceContriStatsProps { id: string; @@ -13,11 +13,17 @@ interface InterfaceContriStatsProps { /** * A component that displays contribution statistics. * - * @param props - The properties passed to the component, including `recentAmount`, `highestAmount`, and `totalAmount`. + * @param recentAmount - The most recent contribution amount. + * @param highestAmount - The highest contribution amount. + * @param totalAmount - The total contribution amount. * * @returns JSX.Element - The rendered component displaying the contribution stats. */ -function ContriStats(props: InterfaceContriStatsProps): JSX.Element { +function ContriStats({ + recentAmount, + highestAmount, + totalAmount, +}: InterfaceContriStatsProps): JSX.Element { const { t } = useTranslation('translation', { keyPrefix: 'contriStats', }); @@ -25,15 +31,16 @@ function ContriStats(props: InterfaceContriStatsProps): JSX.Element { return ( <>

- {t('recentContribution')}: $ {props.recentAmount} + {t('recentContribution')}: $ {recentAmount}

- {t('highestContribution')}: $ {props.highestAmount} + {t('highestContribution')}: $ {highestAmount}

- {t('totalContribution')}: $ {props.totalAmount} + {t('totalContribution')}: $ {totalAmount}

); } + export default ContriStats; diff --git a/src/components/DynamicDropDown/DynamicDropDown.module.css b/src/components/DynamicDropDown/DynamicDropDown.module.css index 0edf85b621..3cd40fe35d 100644 --- a/src/components/DynamicDropDown/DynamicDropDown.module.css +++ b/src/components/DynamicDropDown/DynamicDropDown.module.css @@ -1,6 +1,7 @@ .dropwdownToggle { background-color: #f1f3f6; color: black; + width: 100%; border: none; padding: 0.5rem; text-align: left; diff --git a/src/components/DynamicDropDown/DynamicDropDown.spec.tsx b/src/components/DynamicDropDown/DynamicDropDown.spec.tsx new file mode 100644 index 0000000000..85c3208a20 --- /dev/null +++ b/src/components/DynamicDropDown/DynamicDropDown.spec.tsx @@ -0,0 +1,150 @@ +import React from 'react'; +import { + render, + screen, + act, + waitFor, + fireEvent, +} from '@testing-library/react'; +import DynamicDropDown from './DynamicDropDown'; +import { BrowserRouter } from 'react-router-dom'; +import { I18nextProvider } from 'react-i18next'; +import i18nForTest from 'utils/i18nForTest'; +import userEvent from '@testing-library/user-event'; +import { vi, expect, it } from 'vitest'; + +describe('DynamicDropDown component', () => { + it('renders and handles selection correctly', async () => { + const formData = { fieldName: 'value2' }; + const setFormData = vi.fn(); + + render( + + + + + , + ); + + // Verify that the dropdown container is rendered + const containerElement = screen.getByTestId('fieldname-dropdown-container'); + expect(containerElement).toBeInTheDocument(); + + // Verify that the dropdown button displays the correct initial label + const dropdownButton = screen.getByTestId('fieldname-dropdown-btn'); + expect(dropdownButton).toHaveTextContent('Label 2'); + + // Open the dropdown menu + await act(async () => { + userEvent.click(dropdownButton); + }); + + // Select the first option in the dropdown + const optionElement = screen.getByTestId('change-fieldname-btn-TEST'); + await act(async () => { + userEvent.click(optionElement); + }); + + // Verify that the setFormData function was called with the correct arguments + expect(setFormData).toHaveBeenCalledWith({ fieldName: 'TEST' }); + + // Verify that the dropdown button displays the updated label + await waitFor(() => { + expect(dropdownButton).toHaveTextContent('Label 2'); + }); + }); + it('calls custom handleChange function when provided', async () => { + const formData = { fieldName: 'value1' }; + const setFormData = vi.fn(); + const customHandleChange = vi.fn(); + + render( + + + + + , + ); + + const dropdownButton = screen.getByTestId('fieldname-dropdown-btn'); + await act(async () => { + userEvent.click(dropdownButton); + }); + + const optionElement = screen.getByTestId('change-fieldname-btn-value2'); + await act(async () => { + userEvent.click(optionElement); + }); + + expect(customHandleChange).toHaveBeenCalledTimes(1); + expect(customHandleChange).toHaveBeenCalledWith( + expect.objectContaining({ + target: expect.objectContaining({ + name: 'fieldName', + value: 'value2', + }), + }), + ); + expect(setFormData).not.toHaveBeenCalled(); + }); + it('handles keyboard navigation correctly', async () => { + const formData = { fieldName: 'value1' }; + const setFormData = vi.fn(); + + render( + + + + + , + ); + + // Open dropdown + const dropdownButton = screen.getByTestId('fieldname-dropdown-btn'); + await act(async () => { + userEvent.click(dropdownButton); + }); + + // Get dropdown menu + const dropdownMenu = screen.getByTestId('fieldname-dropdown-menu'); + + // Simulate Enter key press + await act(async () => { + fireEvent.keyDown(dropdownMenu, { key: 'Enter' }); + }); + + // Simulate Space key press + await act(async () => { + fireEvent.keyDown(dropdownMenu, { key: ' ' }); + }); + + // Verify the dropdown menu behavior + const option = screen.getByTestId('change-fieldname-btn-value2'); + expect(option).toBeInTheDocument(); + }); +}); diff --git a/src/components/DynamicDropDown/DynamicDropDown.test.tsx b/src/components/DynamicDropDown/DynamicDropDown.test.tsx deleted file mode 100644 index c77ac5aebf..0000000000 --- a/src/components/DynamicDropDown/DynamicDropDown.test.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import React from 'react'; -import { render, screen, act, waitFor } from '@testing-library/react'; -import DynamicDropDown from './DynamicDropDown'; -import { BrowserRouter } from 'react-router-dom'; -import { I18nextProvider } from 'react-i18next'; -import i18nForTest from 'utils/i18nForTest'; -import userEvent from '@testing-library/user-event'; - -async function wait(ms = 100): Promise { - await act(() => { - return new Promise((resolve) => { - setTimeout(resolve, ms); - }); - }); -} - -describe('DynamicDropDown component', () => { - test('renders with name and alt attribute', async () => { - const [formData, setFormData] = [ - { - fieldName: 'TEST', - }, - jest.fn(), - ]; - - render( - - - - - , - ); - const containterElement = screen.getByTestId( - 'fieldname-dropdown-container', - ); - await act(async () => { - userEvent.click(containterElement); - }); - - const optionButton = screen.getByTestId('fieldname-dropdown-btn'); - - await act(async () => { - userEvent.click(optionButton); - }); - - const optionElement = screen.getByTestId('change-fieldname-btn-TEST'); - await act(async () => { - userEvent.click(optionElement); - }); - await wait(); - expect(containterElement).toBeInTheDocument(); - await waitFor(() => { - expect(optionButton).toHaveTextContent('label1'); - }); - }); -}); diff --git a/src/components/DynamicDropDown/DynamicDropDown.tsx b/src/components/DynamicDropDown/DynamicDropDown.tsx index fac8b8fd85..05cd064ac2 100644 --- a/src/components/DynamicDropDown/DynamicDropDown.tsx +++ b/src/components/DynamicDropDown/DynamicDropDown.tsx @@ -5,14 +5,15 @@ import styles from './DynamicDropDown.module.css'; /** * Props for the DynamicDropDown component. */ -interface InterfaceChangeDropDownProps { +interface InterfaceChangeDropDownProps { parentContainerStyle?: string; btnStyle?: string; btnTextStyle?: string; - setFormState: React.Dispatch>; - formState: any; - fieldOptions: { value: string; label: string }[]; // Field options for dropdown - fieldName: string; // Field name for labeling + setFormState: React.Dispatch>; + formState: T; + fieldOptions: { value: string; label: string }[]; + fieldName: string; + handleChange?: (e: React.ChangeEvent) => void; } /** @@ -27,57 +28,74 @@ interface InterfaceChangeDropDownProps { * @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. + * @param handleChange - Optional callback function when selection changes * @returns JSX.Element - The rendered dropdown component. */ -const DynamicDropDown = ({ +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. - */ + handleChange, +}: InterfaceChangeDropDownProps): JSX.Element => { const handleFieldChange = (value: string): void => { - setFormState({ ...formState, [fieldName]: value }); + if (handleChange) { + const event = { + target: { + name: fieldName, + value: value, + }, + } as React.ChangeEvent; + handleChange(event); + } else { + 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 = fieldOptions.find( (option) => option.value === value, ); - return selectedOption ? selectedOption.label : `None`; + return selectedOption ? selectedOption.label : 'None'; }; return ( - + { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault(); + const focused = document.activeElement; + if (focused instanceof HTMLElement) { + focused.click(); + } + } + }} + > {fieldOptions.map((option, index: number) => ( handleFieldChange(option.value)} data-testid={`change-${fieldName.toLowerCase()}-btn-${option.value}`} + role="option" + aria-selected={option.value === formState[fieldName]} > {option.label} diff --git a/src/components/EditCustomFieldDropDown/EditCustomFieldDropDown.test.tsx b/src/components/EditCustomFieldDropDown/EditCustomFieldDropDown.spec.tsx similarity index 90% rename from src/components/EditCustomFieldDropDown/EditCustomFieldDropDown.test.tsx rename to src/components/EditCustomFieldDropDown/EditCustomFieldDropDown.spec.tsx index 19d2249a43..4119800dd1 100644 --- a/src/components/EditCustomFieldDropDown/EditCustomFieldDropDown.test.tsx +++ b/src/components/EditCustomFieldDropDown/EditCustomFieldDropDown.spec.tsx @@ -8,6 +8,7 @@ import availableFieldTypes from 'utils/fieldTypes'; import { I18nextProvider } from 'react-i18next'; import i18nForTest from 'utils/i18nForTest'; import type { InterfaceCustomFieldData } from 'utils/interfaces'; +import { describe, it, expect } from 'vitest'; async function wait(ms = 100): Promise { await act(() => { @@ -18,7 +19,7 @@ async function wait(ms = 100): Promise { } describe('Testing Custom Field Dropdown', () => { - test('Component Should be rendered properly', async () => { + it('Component Should be rendered properly', async () => { const customFieldData = { type: 'Number', name: 'Age', @@ -26,11 +27,10 @@ describe('Testing Custom Field Dropdown', () => { const setCustomFieldData: Dispatch< SetStateAction - > = (val) => { - { - val; - } + > = () => { + // Intentionally left blank for testing purposes }; + const props = { customFieldData: customFieldData as InterfaceCustomFieldData, setCustomFieldData: setCustomFieldData, diff --git a/src/components/EventCalendar/EventCalendar.module.css b/src/components/EventCalendar/EventCalendar.module.css index 67ecd2dec6..607d750f85 100644 --- a/src/components/EventCalendar/EventCalendar.module.css +++ b/src/components/EventCalendar/EventCalendar.module.css @@ -2,20 +2,23 @@ font-family: sans-serif; font-size: 1.2rem; margin-bottom: 20px; - background: rgb(255, 255, 255); + background: var(--grey-bg-color); border-radius: 10px; padding: 5px; } + .calendar__header { display: flex; margin-bottom: 2rem; align-items: center; margin: 0px 10px 0px 10px; } + .input { flex: 1; position: relative; } + .calendar__header_month { margin: 0.5rem; color: #707070; @@ -25,17 +28,37 @@ gap: 23px; flex-direction: row; } + .calendar__header_month div { font-weight: 400; color: black; font-family: Outfit; } + +.searchbutton { + background-color: var(--search-button-bg); + border-color: var(--search-button-border); + position: absolute; + z-index: 10; + bottom: 0; + right: 0; + display: flex; + justify-content: center; + align-items: center; +} + +.searchbutton:hover { + background-color: var(--search-button-bg); + border-color: var(--search-button-border); +} + .space { flex: 1; display: flex; align-items: center; justify-content: space-around; } + .button { border-radius: 100px; color: #707070; @@ -52,10 +75,12 @@ font-family: Outfit; height: 60px; } + .calendar__scroll { height: 80vh; padding: 10px; } + .weekday { display: flex; justify-content: center; @@ -63,11 +88,13 @@ background-color: white; font-weight: 600; } + .calendar__days { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); grid-template-rows: repeat(6, 1fr); } + .calendar_hour_text_container { display: flex; flex-direction: row; @@ -75,6 +102,7 @@ border-right: 1px solid #8d8d8d55; width: 40px; } + .calendar_hour_text { top: -10px; left: -5px; @@ -82,6 +110,7 @@ color: #707070; font-size: 12px; } + .calendar_timezone_text { top: -10px; left: -11px; @@ -89,6 +118,7 @@ color: #707070; font-size: 9px; } + .calendar_hour_block { display: flex; flex-direction: row; @@ -97,18 +127,22 @@ height: 50px; border-bottom-right-radius: 5px; } + .event_list_parent { position: relative; width: 100%; } + .event_list_parent_current { background-color: #def6e1; position: relative; width: 100%; } + .dummyWidth { width: 1px; } + .day { background-color: #ffffff; padding-left: 0.3rem; @@ -122,26 +156,32 @@ height: 9rem; position: relative; } + .day_weekends { background-color: rgba(49, 187, 107, 0.2); } + .day__outside { background-color: white; color: #89898996; } + .day__selected { background-color: #007bff; color: #707070; } + .day__today { background-color: #def6e1; font-weight: 700; text-decoration: underline; color: #31bb6b; } + .day__events { background-color: white; } + .btn__today { transition: ease-in all 200ms; font-family: Arial; @@ -152,6 +192,7 @@ margin-left: 20px; border: none; } + .btnsContainer { display: flex; margin: 2.5rem 0 2.5rem 0; @@ -169,10 +210,17 @@ } .dropdown { - border-color: #31bb6b; + border: 1px solid var(--dropdown-border-color); background-color: white; - color: #31bb6b; - box-shadow: 0px 2px 1px rgba(49, 187, 107, 0.5); /* Added blur effect */ + color: var(--dropdown-text-color); + box-shadow: 0px 2px 1px var(--grey-bg-color); + /* Added blur effect */ +} + +.dropdown:is(:hover, :focus, :active, :focus-visible, .show) { + background-color: transparent !important; + border: 1px solid var(--dropdown-border-color); + color: var(--dropdown-text-color) !important; } .btnsContainer .input { @@ -187,6 +235,7 @@ .btnsContainer .input button { width: 52px; } + .searchBtn { margin-bottom: 10px; } @@ -195,12 +244,14 @@ margin-top: 10px; margin-bottom: 10px; background-color: white; - box-shadow: 0 1px 1px #31bb6b; + box-shadow: 0 1px 1px var(--search-button-bg); } + .inputField > button { padding-top: 10px; padding-bottom: 10px; } + .btn__more { border: 0px; font-size: 14px; @@ -212,6 +263,7 @@ display: block; margin: 2px; } + .btn__more:hover { color: #454645; } @@ -219,16 +271,24 @@ .expand_event_list { display: block; } -.list_container { - padding: 5px; - width: fit-content; - display: flex; - flex-direction: row; -} .event_list_hour { display: flex; flex-direction: row; } + +.createButton { + background-color: var(--grey-bg-color) !important; + color: black !important; + + border: 1px solid var(--dropdown-border-color); +} + +.createButton:hover { + background-color: var(--grey-bg-color) !important; + color: black !important; + border: 1px solid var(--dropdown-border-color) !important; +} + .expand_list_container { width: 200px; max-height: 250px; @@ -243,24 +303,28 @@ border-radius: 5px; margin: 5px; } + .flex_grow { flex-grow: 1; } -@media only screen and (max-width: 700px) { +@media only screen and (max-width: var(--mobile-breakpoint)) { + /** @breakpoint --mobile-breakpoint: 768px */ .event_list { display: none; } + .expand_list_container { width: 150px; padding: 4px 4px 0px 4px; } + .day { height: 5rem; } } -@media only screen and (max-width: 500px) { +@media only screen and (max-width: var(--small-mobile-breakpoint)) { .btn__more { font-size: 12px; } @@ -273,6 +337,22 @@ gap: 10px; margin-top: 35px; } +.base_card { + flex: 1; + padding: 20px; + border-radius: 10px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15); +} + +.holidays_card { + composes: base_card; + background-color: var(--holiday-card-bg); +} + +.events_card { + composes: base_card; + background-color: #ffffff; +} .card__holidays { background-color: rgba(246, 242, 229, 1); display: flex; @@ -285,24 +365,29 @@ overflow: hidden; white-space: nowrap; } + .month__holidays { display: flex; flex-direction: column; } + .holiday__data { display: flex; flex-direction: row; gap: 10px; } + .holiday__date { font-size: 20px; color: rgba(234, 183, 86, 1); font-weight: 700; } + .holiday__name { font-size: 20px; margin-left: 35px; } + .card__events { background-color: rgba(244, 244, 244, 1); display: flex; @@ -312,21 +397,25 @@ border-radius: 20px; padding: 30px; } + .innercard__events { display: flex; flex-direction: row; align-items: center; gap: 1rem; } + .innercard__events p { margin-bottom: 0; } + .orgEvent__color { height: 15px; width: 40px; background-color: rgba(82, 172, 255, 0.5); border-radius: 10px; } + .holidays__color { height: 15px; width: 40px; @@ -334,9 +423,150 @@ border-radius: 10px; } -.userEvents__color { - height: 15px; - width: 40px; - background: rgba(146, 200, 141, 0.5); +.baseIndicator { + border-radius: 5px; + width: 20px; + height: 12px; + display: inline-block; +} + +.holidayText { + font-size: 14px; + color: #555555; +} +.eventsLegend { + display: flex; + align-items: center; + gap: 8px; +} + +.list_container { + padding: 5px; + width: fit-content; + display: flex; + align-items: center; + gap: var(--indicator-spacing); +} + +.holidayIndicator { + composes: baseIndicator; + background-color: rgba(0, 0, 0, 0.15); +} + +:root { + /* Color scheme for holiday-related elements */ + --color-user-event: rgba(139, 195, 74, 1); + /* Holiday colors */ + --color-holiday-indicator: rgba(0, 0, 0, 0.15); + --color-holiday-date: rgba(255, 152, 0, 1); + /* Breakpoints for responsive design */ + --mobile-breakpoint: 700px; + --small-mobile-breakpoint: 480px; + --text-color-primary: rgba(51, 51, 51, 1); + --text-color-secondary: rgba(85, 85, 85, 1); + /* Card styles */ + --card-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + --holiday-card-bg: #f6f2e5; + --holiday-date-color: #d35400; + --indicator-spacing: 8px; + /* Interactive states */ + --hover-bg-color: rgba(0, 0, 0, 0.05); +} +.organizationIndicator { + composes: baseIndicator; + background-color: rgba(82, 172, 255, 0.5); +} + +.legendText { + font-size: 14px; + color: #555555; +} +@media only screen and (max-width: var(--mobile-breakpoint)) { + .list_container, + .eventsLegend { + gap: 4px; + } + + .holidayIndicator, + .organizationIndicator { + width: 16px; + height: 10px; + } + + .holidayText, + .legendText { + font-size: 12px; + } +} +.card_title { + font-size: 16px; + font-weight: 600; + color: var(--text-color-primary); + margin-bottom: 15px; +} + +.card_list { + list-style: none; + padding: 0; + margin: 0; +} + +.card_list_item { + display: flex; + align-items: center; + margin-bottom: 10px; + font-size: 14px; + color: var(--text-color-secondary); +} + +.holiday_date { + font-weight: 500; + margin-right: 10px; + color: var(--holiday-date-color); +} + +.calendar_infocards { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: flex-start; + gap: 20px; + padding: 20px; + background-color: var(--grey-bg-color); +} +.holidays_card, +.events_card { + flex: 1; + padding: 20px; border-radius: 10px; + box-shadow: var(--card-shadow); +} + +.holidays_card { + background-color: var(--holiday-card-bg); +} + +.events_card { + background-color: white; +} + +.legend { + display: flex; + flex-direction: column; + gap: 12px; +} + +.userEvents__color { + composes: baseIndicator; + display: inline-block; + background-color: rgba(139, 195, 74, 1); +} + +.card_list_item:hover { + background-color: var(--hover-bg-color); + transition: background-color 0.2s ease; +} +.card_list_item:focus-visible { + background-color: var(--hover-bg-color); + transition: background-color 0.2s ease; } diff --git a/src/components/EventCalendar/EventCalendar.test.tsx b/src/components/EventCalendar/EventCalendar.spec.tsx similarity index 88% rename from src/components/EventCalendar/EventCalendar.test.tsx rename to src/components/EventCalendar/EventCalendar.spec.tsx index caca516763..4dfd0548d6 100644 --- a/src/components/EventCalendar/EventCalendar.test.tsx +++ b/src/components/EventCalendar/EventCalendar.spec.tsx @@ -13,6 +13,7 @@ import i18nForTest from 'utils/i18nForTest'; import { StaticMockLink } from 'utils/StaticMockLink'; import { weekdays, months } from './constants'; import { BrowserRouter as Router } from 'react-router-dom'; +import { vi } from 'vitest'; const eventData = [ { @@ -122,7 +123,7 @@ describe('Calendar', () => { }); afterEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); }); it('should render the current month and year', () => { @@ -286,13 +287,14 @@ describe('Calendar', () => { // expect(todayCell).toHaveClass(styles.day__today); }); it('Should handle window resize in day view', async () => { + const date = new Date().toISOString().split('T')[0]; const multipleEventData = [ { _id: '1', title: 'Event 1', description: 'This is event 1', - startDate: new Date().toISOString().split('T')[0], - endDate: new Date().toISOString().split('T')[0], + startDate: date, + endDate: date, location: 'Los Angeles', startTime: null, endTime: null, @@ -307,8 +309,8 @@ describe('Calendar', () => { _id: '2', title: 'Event 2', description: 'This is event 2', - startDate: new Date().toISOString().split('T')[0], - endDate: new Date().toISOString().split('T')[0], + startDate: date, + endDate: date, location: 'Los Angeles', startTime: null, endTime: null, @@ -323,8 +325,8 @@ describe('Calendar', () => { _id: '3', title: 'Event 3', description: 'This is event 3', - startDate: new Date().toISOString().split('T')[0], - endDate: new Date().toISOString().split('T')[0], + startDate: date, + endDate: date, location: 'Los Angeles', startTime: '14:00', endTime: '16:00', @@ -339,8 +341,8 @@ describe('Calendar', () => { _id: '4', title: 'Event 4', description: 'This is event 4', - startDate: new Date().toISOString().split('T')[0], - endDate: new Date().toISOString().split('T')[0], + startDate: date, + endDate: date, location: 'Los Angeles', startTime: '14:00', endTime: '16:00', @@ -355,8 +357,8 @@ describe('Calendar', () => { _id: '5', title: 'Event 5', description: 'This is event 5', - startDate: new Date().toISOString().split('T')[0], - endDate: new Date().toISOString().split('T')[0], + startDate: date, + endDate: date, location: 'Los Angeles', startTime: '17:00', endTime: '19:00', @@ -372,14 +374,40 @@ describe('Calendar', () => { - + - , , ); + + // Simulate window resize and check if components respond correctly + await act(async () => { + window.innerWidth = 500; // Set the window width to <= 700 + window.dispatchEvent(new Event('resize')); + }); + + // Check for "View all" button if there are more than 2 events + const viewAllButton = await screen.findAllByTestId('more'); + console.log('hi', viewAllButton); // This will show the buttons found in the test + expect(viewAllButton.length).toBeGreaterThan(0); + + // Simulate clicking the "View all" button to expand the list + fireEvent.click(viewAllButton[0]); + + const event5 = screen.queryByText('Event 5'); + expect(event5).toBeNull(); + + const viewLessButtons = screen.getAllByText('View less'); + expect(viewLessButtons.length).toBeGreaterThan(0); + + // Simulate clicking "View less" to collapse the list + fireEvent.click(viewLessButtons[0]); + const viewAllButtons = screen.getAllByText('View all'); + expect(viewAllButtons.length).toBeGreaterThan(0); + + // Reset the window size to avoid side effects for other tests await act(async () => { - window.innerWidth = 500; + window.innerWidth = 1024; window.dispatchEvent(new Event('resize')); }); }); diff --git a/src/components/EventCalendar/EventCalendar.tsx b/src/components/EventCalendar/EventCalendar.tsx index fb76eb597c..ebcf8be942 100644 --- a/src/components/EventCalendar/EventCalendar.tsx +++ b/src/components/EventCalendar/EventCalendar.tsx @@ -1,16 +1,14 @@ import EventListCard from 'components/EventListCard/EventListCard'; import dayjs from 'dayjs'; +import React, { useState, useEffect, useMemo } from 'react'; import Button from 'react-bootstrap/Button'; -import React, { useState, useEffect } from 'react'; import styles from './EventCalendar.module.css'; import { ChevronLeft, ChevronRight } from '@mui/icons-material'; -import CurrentHourIndicator from 'components/CurrentHourIndicator/CurrentHourIndicator'; import { ViewType } from 'screens/OrganizationEvents/OrganizationEvents'; import HolidayCard from '../HolidayCards/HolidayCard'; -import { holidays, hours, months, weekdays } from './constants'; +import { holidays, months, weekdays } from './constants'; import type { InterfaceRecurrenceRule } from 'utils/recurrenceUtils'; import YearlyEventCalender from './YearlyEventCalender'; - interface InterfaceEventListCardProps { userRole?: string; key?: string; @@ -75,7 +73,6 @@ const Calendar: React.FC = ({ ); const [expanded, setExpanded] = useState(-1); const [windowWidth, setWindowWidth] = useState(window.screen.width); - useEffect(() => { function handleResize(): void { setWindowWidth(window.screen.width); @@ -93,7 +90,7 @@ const Calendar: React.FC = ({ const data: InterfaceEventListCardProps[] = []; if (userRole === Role.SUPERADMIN) return eventData; // Hard to test all the cases - /* istanbul ignore next */ + if (userRole === Role.ADMIN) { eventData?.forEach((event) => { if (event.isPublic) data.push(event); @@ -130,7 +127,6 @@ const Calendar: React.FC = ({ * Moves the calendar view to the previous month. */ const handlePrevMonth = (): void => { - /*istanbul ignore next*/ if (currentMonth === 0) { setCurrentMonth(11); setCurrentYear(currentYear - 1); @@ -139,11 +135,22 @@ const Calendar: React.FC = ({ } }; - /** - * Moves the calendar view to the next month. - */ + const filteredHolidays = useMemo(() => { + return Array.isArray(holidays) + ? holidays.filter((holiday) => { + if (!holiday.date) { + if (process.env.NODE_ENV !== 'test') { + console.warn(`Holiday "${holiday.name}" has no date specified.`); + } + return false; + } + const holidayMonth = dayjs(holiday.date, 'MM-DD', true).month(); + return holidayMonth === currentMonth; + }) + : []; + }, [holidays, currentMonth]); + const handleNextMonth = (): void => { - /*istanbul ignore next*/ if (currentMonth === 11) { setCurrentMonth(0); setCurrentYear(currentYear + 1); @@ -151,12 +158,7 @@ const Calendar: React.FC = ({ setCurrentMonth(currentMonth + 1); } }; - - /** - * Moves the calendar view to the previous date. - */ const handlePrevDate = (): void => { - /*istanbul ignore next*/ if (currentDate > 1) { setCurrentDate(currentDate - 1); } else { @@ -175,15 +177,13 @@ const Calendar: React.FC = ({ } } }; - /*istanbul ignore next*/ + const handleNextDate = (): void => { - /*istanbul ignore next*/ const lastDayOfCurrentMonth = new Date( currentYear, currentMonth - 1, 0, ).getDate(); - /*istanbul ignore next*/ if (currentDate < lastDayOfCurrentMonth) { setCurrentDate(currentDate + 1); } else { @@ -198,11 +198,7 @@ const Calendar: React.FC = ({ } }; - /** - * Moves the calendar view to today's date. - */ const handleTodayButton = (): void => { - /*istanbul ignore next*/ setCurrentYear(today.getFullYear()); setCurrentMonth(today.getMonth()); setCurrentDate(today.getDate()); @@ -215,7 +211,6 @@ const Calendar: React.FC = ({ '0', )}:${String(Math.abs(new Date().getTimezoneOffset()) % 60).padStart(2, '0')}`; - /*istanbul ignore next*/ const renderHours = (): JSX.Element => { const toggleExpand = (index: number): void => { if (expanded === index) { @@ -225,11 +220,9 @@ const Calendar: React.FC = ({ } }; - /*istanbul ignore next*/ const allDayEventsList: JSX.Element[] = events ?.filter((datas) => { - /*istanbul ignore next*/ const currDate = new Date(currentYear, currentMonth, currentDate); if ( datas.startTime == undefined && @@ -273,6 +266,17 @@ const Calendar: React.FC = ({ ); }) || []; + const shouldShowViewMore = useMemo(() => { + return ( + allDayEventsList.length > 2 || + (windowWidth <= 700 && allDayEventsList.length > 0) + ); + }, [allDayEventsList.length, windowWidth]); + + const handleExpandClick: () => void = () => { + toggleExpand(-100); + }; + return ( <>
@@ -293,7 +297,6 @@ const Calendar: React.FC = ({ ? styles.expand_list_container : styles.list_container } - style={{ width: 'fit-content' }} >
= ({ : styles.event_list_hour } > - {expanded === -100 - ? allDayEventsList - : allDayEventsList?.slice(0, 1)} + {Array.isArray(allDayEventsList) && + allDayEventsList.length > 0 ? ( + expanded === -100 ? ( + allDayEventsList + ) : ( + allDayEventsList.slice(0, 1) + ) + ) : ( +

+ No events available +

+ )}
- {(allDayEventsList?.length > 2 || - (windowWidth <= 700 && allDayEventsList?.length > 0)) && ( + {Array.isArray(allDayEventsList) && ( )}
- {hours.map((hour, index) => { - const timeEventsList: JSX.Element[] = - events - ?.filter((datas) => { - const currDate = new Date( - currentYear, - currentMonth, - currentDate, - ); - - if ( - parseInt(datas.startTime?.slice(0, 2) as string).toString() == - (index % 24).toString() && - datas.startDate == dayjs(currDate).format('YYYY-MM-DD') - ) { - return datas; - } - }) - .map((datas: InterfaceEventListCardProps) => { - const attendees: { _id: string }[] = []; - datas.attendees?.forEach((attendee: { _id: string }) => { - const r = { - _id: attendee._id, - }; - - attendees.push(r); - }); - - return ( - - ); - }) || []; - /*istanbul ignore next*/ - return ( -
-
-

{`${hour}`}

+ +
+
+

Holidays

+
    + {filteredHolidays.map((holiday, index) => ( +
  • + + {months[parseInt(holiday.date.slice(0, 2), 10) - 1]}{' '} + {holiday.date.slice(3)} + + {holiday.name} +
  • + ))} +
+
+ +
+

Events

+
+
+ + Holidays
-
-
0 - ? styles.event_list_parent_current - : styles.event_list_parent - } - > - {index % 24 == new Date().getHours() && - new Date().getDate() == currentDate && ( - - )} -
-
- {/*istanbul ignore next*/} - {expanded === index - ? timeEventsList - : timeEventsList?.slice(0, 1)} -
- {(timeEventsList?.length > 1 || - (windowWidth <= 700 && timeEventsList?.length > 0)) && ( - - )} -
+
+ + + Events Created by Organization + +
+
+ + + Events Created by User +
- ); - })} +
+
); }; @@ -457,22 +407,21 @@ const Calendar: React.FC = ({ return days.map((date, index) => { const className = [ date.getDay() === 0 || date.getDay() === 6 ? styles.day_weekends : '', - date.toLocaleDateString() === today.toLocaleDateString() //Styling for today day cell + date.toLocaleDateString() === today.toLocaleDateString() ? styles.day__today : '', - date.getMonth() !== currentMonth ? styles.day__outside : '', //Styling for days outside the current month + date.getMonth() !== currentMonth ? styles.day__outside : '', selectedDate?.getTime() === date.getTime() ? styles.day__selected : '', styles.day, ].join(' '); const toggleExpand = (index: number): void => { - /*istanbul ignore next*/ if (expanded === index) { setExpanded(-1); } else { setExpanded(index); } }; - /*istanbul ignore next*/ + const allEventsList: JSX.Element[] = events ?.filter((datas) => { @@ -514,13 +463,12 @@ const Calendar: React.FC = ({ ); }) || []; - const holidayList: JSX.Element[] = holidays - .filter((holiday) => { - if (holiday.date == dayjs(date).format('MM-DD')) return holiday; - }) + const holidayList: JSX.Element[] = filteredHolidays + .filter((holiday) => holiday.date === dayjs(date).format('MM-DD')) .map((holiday) => { return ; }); + return (
= ({ >
{holidayList}
- { - /*istanbul ignore next*/ - expanded === index - ? allEventsList - : holidayList?.length > 0 - ? /*istanbul ignore next*/ - allEventsList?.slice(0, 1) - : allEventsList?.slice(0, 2) - } + {expanded === index + ? allEventsList + : holidayList?.length > 0 + ? allEventsList?.slice(0, 1) + : allEventsList?.slice(0, 2)}
{(allEventsList?.length > 2 || (windowWidth <= 700 && allEventsList?.length > 0)) && ( - /*istanbul ignore next*/ )}
@@ -621,7 +560,7 @@ const Calendar: React.FC = ({ )}
{viewType == ViewType.MONTH ? ( -
+ <>
{weekdays.map((weekday, index) => (
@@ -630,18 +569,14 @@ const Calendar: React.FC = ({ ))}
{renderDays()}
-
+ + ) : viewType == ViewType.YEAR ? ( + ) : ( - // -
- {viewType == ViewType.YEAR ? ( - - ) : ( -
{renderHours()}
- )} -
+
{renderHours()}
)}
+
{viewType == ViewType.YEAR ? ( diff --git a/src/components/EventCalendar/EventHeader.test.tsx b/src/components/EventCalendar/EventHeader.spec.tsx similarity index 92% rename from src/components/EventCalendar/EventHeader.test.tsx rename to src/components/EventCalendar/EventHeader.spec.tsx index e18d066306..be1ba4bd78 100644 --- a/src/components/EventCalendar/EventHeader.test.tsx +++ b/src/components/EventCalendar/EventHeader.spec.tsx @@ -4,11 +4,20 @@ import EventHeader from './EventHeader'; import { ViewType } from '../../screens/OrganizationEvents/OrganizationEvents'; import { I18nextProvider } from 'react-i18next'; import i18nForTest from 'utils/i18nForTest'; +import { vi } from 'vitest'; describe('EventHeader Component', () => { const viewType = ViewType.MONTH; - const handleChangeView = jest.fn(); - const showInviteModal = jest.fn(); + + /** + * Mock function to handle view type changes. + */ + const handleChangeView = vi.fn(); + + /** + * Mock function to handle the display of the invite modal. + */ + const showInviteModal = vi.fn(); it('renders correctly', () => { const { getByTestId } = render( diff --git a/src/components/EventCalendar/EventHeader.tsx b/src/components/EventCalendar/EventHeader.tsx index 1e4653ebf4..08039796e2 100644 --- a/src/components/EventCalendar/EventHeader.tsx +++ b/src/components/EventCalendar/EventHeader.tsx @@ -55,7 +55,7 @@ function eventHeader({ onChange={(e) => setEventName(e.target.value)} />
+

+ {eventData.event.title} +

+

+ {eventData.event.description}

-

- Location: {eventData?.event?.location} +

+ Location: {eventData.event.location}

-

+

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

-
+
+ Recurring Event:{' '} + + {eventData.event.recurring ? 'Active' : 'Inactive'} + +
+
+
+

+ + {eventData.event.startTime !== null + ? `${formatTime(eventData.event.startTime)}` + : ``} + {' '} + + {formatDate(eventData.event.startDate)}{' '} + +

+

{t('to')}

+

+ + {eventData.event.endTime !== null + ? `${formatTime(eventData.event.endTime)}` + : ``} + {' '} + + {formatDate(eventData.event.endDate)}{' '} + +

diff --git a/src/components/EventManagement/EventAgendaItems/EventAgendaItems.module.css b/src/components/EventManagement/EventAgendaItems/EventAgendaItems.module.css deleted file mode 100644 index 9d1c32b766..0000000000 --- a/src/components/EventManagement/EventAgendaItems/EventAgendaItems.module.css +++ /dev/null @@ -1,22 +0,0 @@ -.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.spec.tsx similarity index 87% rename from src/components/EventManagement/EventAgendaItems/EventAgendaItems.test.tsx rename to src/components/EventManagement/EventAgendaItems/EventAgendaItems.spec.tsx index 3bce7ad11e..fabd3312dd 100644 --- a/src/components/EventManagement/EventAgendaItems/EventAgendaItems.test.tsx +++ b/src/components/EventManagement/EventAgendaItems/EventAgendaItems.spec.tsx @@ -7,9 +7,7 @@ import { 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'; @@ -17,11 +15,10 @@ 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 { vi, describe, expect, it, beforeEach } from 'vitest'; import { MOCKS, @@ -29,21 +26,20 @@ import { // MOCKS_ERROR_MUTATION, } from './EventAgendaItemsMocks'; -jest.mock('react-toastify', () => ({ +vi.mock('react-toastify', () => ({ toast: { - success: jest.fn(), - error: jest.fn(), + success: vi.fn(), + error: vi.fn(), }, })); -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useParams: () => ({ eventId: '123' }), +vi.mock('react-router-dom', async () => ({ + ...(await vi.importActual('react-router-dom')), })); //temporarily fixes react-beautiful-dnd droppable method's depreciation error //needs to be fixed in React 19 -jest.spyOn(console, 'error').mockImplementation((message) => { +vi.spyOn(console, 'error').mockImplementation((message) => { if (message.includes('Support for defaultProps will be removed')) { return; } @@ -78,8 +74,18 @@ describe('Testing Agenda Items Components', () => { attachments: [], urls: [], }; - test('Component loads correctly', async () => { - window.location.assign('/event/111/123'); + + beforeEach(() => { + Object.defineProperty(window, 'location', { + configurable: true, + value: { + reload: vi.fn(), + href: 'https://localhost:4321/event/111/123', + }, + }); + }); + + it('Component loads correctly', async () => { const { getByText } = render( @@ -99,8 +105,7 @@ describe('Testing Agenda Items Components', () => { }); }); - test('render error component on unsuccessful agenda item query', async () => { - window.location.assign('/event/111/123'); + it('render error component on unsuccessful agenda item query', async () => { const { queryByText } = render( @@ -122,8 +127,7 @@ describe('Testing Agenda Items Components', () => { }); }); - test('opens and closes the create agenda item modal', async () => { - window.location.assign('/event/111/123'); + it('opens and closes the create agenda item modal', async () => { render( @@ -156,8 +160,7 @@ describe('Testing Agenda Items Components', () => { screen.queryByTestId('createAgendaItemModalCloseBtn'), ); }); - test('creates new agenda item', async () => { - window.location.assign('/event/111/123'); + it('creates new agenda item', async () => { render( diff --git a/src/components/EventManagement/EventAgendaItems/EventAgendaItems.tsx b/src/components/EventManagement/EventAgendaItems/EventAgendaItems.tsx index b49ade4626..9b758a555a 100644 --- a/src/components/EventManagement/EventAgendaItems/EventAgendaItems.tsx +++ b/src/components/EventManagement/EventAgendaItems/EventAgendaItems.tsx @@ -20,7 +20,7 @@ import type { import AgendaItemsContainer from 'components/AgendaItems/AgendaItemsContainer'; import AgendaItemsCreateModal from 'components/AgendaItems/AgendaItemsCreateModal'; -import styles from './EventAgendaItems.module.css'; +import styles from '../../../style/app.module.css'; import Loader from 'components/Loader/Loader'; /** diff --git a/src/components/EventManagement/EventAttendance/Attendance.mocks.ts b/src/components/EventManagement/EventAttendance/Attendance.mocks.ts new file mode 100644 index 0000000000..2dc8c89571 --- /dev/null +++ b/src/components/EventManagement/EventAttendance/Attendance.mocks.ts @@ -0,0 +1,62 @@ +import { EVENT_ATTENDEES } from 'GraphQl/Queries/Queries'; + +export const MOCKS = [ + { + request: { + query: EVENT_ATTENDEES, + variables: {}, // Removed id since it's not required based on error + }, + result: { + data: { + event: { + attendees: [ + { + _id: '6589386a2caa9d8d69087484', + firstName: 'Bruce', + lastName: 'Garza', + gender: null, + birthDate: null, + createdAt: '2023-04-13T10:23:17.742', + eventsAttended: [ + { + __typename: 'Event', + _id: '660fdf7d2c1ef6c7db1649ad', + }, + { + __typename: 'Event', + _id: '660fdd562c1ef6c7db1644f7', + }, + ], + __typename: 'User', + }, + { + _id: '6589386a2caa9d8d69087485', + firstName: 'Jane', + lastName: 'Smith', + gender: null, + birthDate: null, + createdAt: '2023-04-13T10:23:17.742', + eventsAttended: [ + { + __typename: 'Event', + _id: '660fdf7d2c1ef6c7db1649ad', + }, + ], + __typename: 'User', + }, + ], + }, + }, + }, + }, +]; + +export const MOCKS_ERROR = [ + { + request: { + query: EVENT_ATTENDEES, + variables: {}, + }, + error: new Error('An error occurred'), + }, +]; diff --git a/src/components/EventManagement/EventAttendance/AttendedEventList.spec.tsx b/src/components/EventManagement/EventAttendance/AttendedEventList.spec.tsx new file mode 100644 index 0000000000..b365ba89ff --- /dev/null +++ b/src/components/EventManagement/EventAttendance/AttendedEventList.spec.tsx @@ -0,0 +1,120 @@ +import React from 'react'; +import { render, waitFor } from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import AttendedEventList from './AttendedEventList'; +import { EVENT_DETAILS } from 'GraphQl/Queries/Queries'; +import { BrowserRouter } from 'react-router-dom'; +import { I18nextProvider } from 'react-i18next'; +import i18nForTest from 'utils/i18nForTest'; +import { formatDate } from 'utils/dateFormatter'; +import { describe, expect, it } from 'vitest'; + +const mockEvent = { + _id: 'event123', + title: 'Test Event', + description: 'This is a test event description', + startDate: '2023-05-01', + endDate: '2023-05-02', + startTime: '09:00:00', + endTime: '17:00:00', + allDay: false, + location: 'Test Location', + recurring: true, + baseRecurringEvent: { + _id: 'recurringEvent123', + }, + organization: { + _id: 'org456', + members: [ + { _id: 'member1', firstName: 'John', lastName: 'Doe' }, + { _id: 'member2', firstName: 'Jane', lastName: 'Smith' }, + ], + }, + attendees: [{ _id: 'user1' }, { _id: 'user2' }], +}; + +const mocks = [ + { + request: { + query: EVENT_DETAILS, + variables: { id: 'event123' }, + }, + result: { + data: { + event: mockEvent, + }, + }, + }, +]; + +describe('Testing AttendedEventList', () => { + const props = { + eventId: 'event123', + }; + + it('Component renders and displays event details correctly', async () => { + const { queryByText, queryByTitle } = render( + + + + + + + , + ); + + expect(queryByText('Loading...')).toBeInTheDocument(); + + await waitFor(() => { + expect(queryByText('Test Event')).toBeInTheDocument(); + expect(queryByText(formatDate(mockEvent.startDate))).toBeInTheDocument(); + expect(queryByTitle('Event Date')).toBeInTheDocument(); + }); + }); + + it('Component handles error state gracefully', async () => { + const errorMock = [ + { + request: { + query: EVENT_DETAILS, + variables: { id: 'event123' }, + }, + error: new Error('An error occurred'), + }, + ]; + + const { queryByText } = render( + + + + + + + , + ); + + await waitFor(() => { + expect(queryByText('Loading...')).not.toBeInTheDocument(); + // The component doesn't explicitly render an error message, so we just check that the event details are not rendered + expect(queryByText('Test Event')).not.toBeInTheDocument(); + }); + }); + + it('Component renders link with correct URL', async () => { + const { container } = render( + + + + + + + , + ); + + await waitFor(() => { + const link = container.querySelector('a'); + expect(link).not.toBeNull(); + expect(link).toHaveAttribute('href', expect.stringContaining('/event/')); + }); + }); +}); diff --git a/src/components/EventManagement/EventAttendance/AttendedEventList.tsx b/src/components/EventManagement/EventAttendance/AttendedEventList.tsx new file mode 100644 index 0000000000..2d0286feb0 --- /dev/null +++ b/src/components/EventManagement/EventAttendance/AttendedEventList.tsx @@ -0,0 +1,68 @@ +import React from 'react'; +import { TableBody, TableCell, TableRow, Table } from '@mui/material'; +import { EVENT_DETAILS } from 'GraphQl/Queries/Queries'; +import { useQuery } from '@apollo/client'; +import { Link, useParams } from 'react-router-dom'; +import { formatDate } from 'utils/dateFormatter'; +import DateIcon from 'assets/svgs/cardItemDate.svg?react'; +interface InterfaceEventsAttended { + eventId: string; +} +/** + * Component to display a list of events attended by a member + * @param eventId - The ID of the event to display details for + * @returns A table row containing event details with a link to the event + */ +const AttendedEventList: React.FC = ({ eventId }) => { + const { orgId: currentOrg } = useParams(); + const { data, loading, error } = useQuery(EVENT_DETAILS, { + variables: { id: eventId }, + fetchPolicy: 'cache-first', + errorPolicy: 'all', + }); + + if (error || data?.error) { + return

Error loading event details. Please try again later.

; + } + + const event = data?.event ?? null; + + if (loading) return

Loading...

; + return ( + + + + {event && ( + + + + +
+
{event.title}
+
{formatDate(event.startDate)}
+
+ +
+
+ )} +
+
+
+ ); +}; +export default AttendedEventList; diff --git a/src/components/EventManagement/EventAttendance/EventAttendance.spec.tsx b/src/components/EventManagement/EventAttendance/EventAttendance.spec.tsx new file mode 100644 index 0000000000..bff1553cc0 --- /dev/null +++ b/src/components/EventManagement/EventAttendance/EventAttendance.spec.tsx @@ -0,0 +1,147 @@ +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 { BrowserRouter } from 'react-router-dom'; +import { I18nextProvider } from 'react-i18next'; +import EventAttendance from './EventAttendance'; +import { store } from 'state/store'; +import userEvent from '@testing-library/user-event'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import i18n from 'utils/i18nForTest'; +import { MOCKS } from './Attendance.mocks'; +import { vi, describe, beforeEach, afterEach, expect, it } from 'vitest'; + +const link = new StaticMockLink(MOCKS, true); + +async function wait(): Promise { + await waitFor(() => { + return Promise.resolve(); + }); +} +vi.mock('react-chartjs-2', () => ({ + Line: () => null, + Bar: () => null, + Pie: () => null, +})); + +const renderEventAttendance = (): RenderResult => { + return render( + + + + + + + + + , + ); +}; + +describe('Event Attendance Component', () => { + beforeEach(() => { + vi.mock('react-router-dom', async () => ({ + ...(await vi.importActual('react-router-dom')), + })); + }); + + afterEach(() => { + vi.clearAllMocks(); + cleanup(); + }); + + it('Component loads correctly with table headers', async () => { + renderEventAttendance(); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('table-header-row')).toBeInTheDocument(); + expect(screen.getByTestId('header-member-name')).toBeInTheDocument(); + expect(screen.getByTestId('header-status')).toBeInTheDocument(); + }); + }); + + it('Renders attendee data correctly', async () => { + renderEventAttendance(); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('attendee-name-0')).toBeInTheDocument(); + expect(screen.getByTestId('attendee-name-1')).toHaveTextContent( + 'Jane Smith', + ); + }); + }); + + it('Search filters attendees by name correctly', async () => { + renderEventAttendance(); + + await wait(); + + const searchInput = screen.getByTestId('searchByName'); + fireEvent.change(searchInput, { target: { value: 'Bruce' } }); + + await waitFor(() => { + const filteredAttendee = screen.getByTestId('attendee-name-0'); + expect(filteredAttendee).toHaveTextContent('Bruce Garza'); + }); + }); + + it('Sort functionality changes attendee order', async () => { + renderEventAttendance(); + + await wait(); + + const sortDropdown = screen.getByTestId('sort-dropdown'); + userEvent.click(sortDropdown); + userEvent.click(screen.getByText('Sort')); + + await waitFor(() => { + const attendees = screen.getAllByTestId('attendee-name-0'); + expect(attendees[0]).toHaveTextContent('Bruce Garza'); + }); + }); + + it('Date filter shows correct number of attendees', async () => { + renderEventAttendance(); + + await wait(); + + userEvent.click(screen.getByText('Filter: All')); + userEvent.click(screen.getByText('This Month')); + + await waitFor(() => { + expect(screen.getByText('Attendees not Found')).toBeInTheDocument(); + }); + }); + it('Statistics modal opens and closes correctly', async () => { + renderEventAttendance(); + await wait(); + + expect(screen.queryByTestId('attendance-modal')).not.toBeInTheDocument(); + + const statsButton = screen.getByTestId('stats-modal'); + userEvent.click(statsButton); + + await waitFor(() => { + expect(screen.getByTestId('attendance-modal')).toBeInTheDocument(); + }); + + const closeButton = screen.getByTestId('close-button'); + userEvent.click(closeButton); + + await waitFor(() => { + expect(screen.queryByTestId('attendance-modal')).not.toBeInTheDocument(); + }); + }); +}); diff --git a/src/components/EventManagement/EventAttendance/EventAttendance.tsx b/src/components/EventManagement/EventAttendance/EventAttendance.tsx new file mode 100644 index 0000000000..06b047a973 --- /dev/null +++ b/src/components/EventManagement/EventAttendance/EventAttendance.tsx @@ -0,0 +1,376 @@ +import React, { useEffect, useMemo, useState } from 'react'; +import { BiSearch as Search } from 'react-icons/bi'; +import { + Paper, + TableBody, + TableCell, + TableContainer, + TableHead, + TableRow, + Tooltip, +} from '@mui/material'; +import { + Button, + Dropdown, + DropdownButton, + Table, + FormControl, +} from 'react-bootstrap'; +import styles from '../../../style/app.module.css'; +import { useLazyQuery } from '@apollo/client'; +import { EVENT_ATTENDEES } from 'GraphQl/Queries/Queries'; +import { useParams, Link } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; +import { AttendanceStatisticsModal } from './EventStatistics'; +import AttendedEventList from './AttendedEventList'; +import type { InterfaceMember } from './InterfaceEvents'; +enum FilterPeriod { + ThisMonth = 'This Month', + ThisYear = 'This Year', + All = 'All', +} +/** + * Component to manage and display event attendance information + * Includes filtering and sorting functionality for attendees + * @returns JSX element containing the event attendance interface + */ +function EventAttendance(): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'eventAttendance', + }); + const { eventId } = useParams<{ eventId: string }>(); + const { orgId: currentUrl } = useParams(); + const [filteredAttendees, setFilteredAttendees] = useState( + [], + ); + const [sortOrder, setSortOrder] = useState<'ascending' | 'descending'>( + 'ascending', + ); + const [filteringBy, setFilteringBy] = useState( + FilterPeriod.All, + ); + const [show, setShow] = useState(false); + + const sortAttendees = (attendees: InterfaceMember[]): InterfaceMember[] => { + return [...attendees].sort((a, b) => { + const nameA = `${a.firstName} ${a.lastName}`.toLowerCase(); + const nameB = `${b.firstName} ${b.lastName}`.toLowerCase(); + return sortOrder === 'ascending' + ? nameA.localeCompare(nameB) + : /*istanbul ignore next*/ + nameB.localeCompare(nameA); + }); + }; + + const filterAttendees = (attendees: InterfaceMember[]): InterfaceMember[] => { + const now = new Date(); + return filteringBy === 'All' + ? attendees + : attendees.filter((attendee) => { + const attendeeDate = new Date(attendee.createdAt); + const isSameYear = attendeeDate.getFullYear() === now.getFullYear(); + return filteringBy === 'This Month' + ? isSameYear && attendeeDate.getMonth() === now.getMonth() + : /*istanbul ignore next*/ + isSameYear; + }); + }; + + const filterAndSortAttendees = ( + attendees: InterfaceMember[], + ): InterfaceMember[] => { + return sortAttendees(filterAttendees(attendees)); + }; + const searchEventAttendees = (value: string): void => { + const searchValueLower = value.toLowerCase().trim(); + + const filtered = (memberData?.event?.attendees ?? []).filter( + (attendee: InterfaceMember) => { + const fullName = + `${attendee.firstName} ${attendee.lastName}`.toLowerCase(); + return ( + attendee.firstName?.toLowerCase().includes(searchValueLower) || + attendee.lastName?.toLowerCase().includes(searchValueLower) || + attendee.email?.toLowerCase().includes(searchValueLower) || + fullName.includes(searchValueLower) + ); + }, + ); + + const finalFiltered = filterAndSortAttendees(filtered); + setFilteredAttendees(finalFiltered); + }; + const showModal = (): void => setShow(true); + const handleClose = (): void => setShow(false); + + const statistics = useMemo(() => { + const totalMembers = filteredAttendees.length; + const membersAttended = filteredAttendees.filter( + (member) => member?.eventsAttended && member.eventsAttended.length > 0, + ).length; + const attendanceRate = + totalMembers > 0 + ? Number(((membersAttended / totalMembers) * 100).toFixed(2)) + : 0; + + return { totalMembers, membersAttended, attendanceRate }; + }, [filteredAttendees]); + + const [getEventAttendees, { data: memberData, loading, error }] = + useLazyQuery(EVENT_ATTENDEES, { + variables: { + id: eventId, + }, + fetchPolicy: 'cache-and-network', + nextFetchPolicy: 'cache-first', + errorPolicy: 'all', + notifyOnNetworkStatusChange: true, + }); + + useEffect(() => { + if (memberData?.event?.attendees) { + const updatedAttendees = filterAndSortAttendees( + memberData.event.attendees, + ); + setFilteredAttendees(updatedAttendees); + } + }, [sortOrder, filteringBy, memberData]); + + useEffect(() => { + getEventAttendees(); + }, [eventId, getEventAttendees]); + + if (loading) return

{t('loading')}

; + /*istanbul ignore next*/ + if (error) return

{error.message}

; + + return ( +
+ +
+
+ +
+
+
+ searchEventAttendees(e.target.value)} + /> + +
+ + + Sort + Filter: {filteringBy} + + } + onSelect={(eventKey) => setFilteringBy(eventKey as FilterPeriod)} + > + This Month + This Year + All + + + Sort + Sort + + } + onSelect={ + /*istanbul ignore next*/ + (eventKey) => setSortOrder(eventKey as 'ascending' | 'descending') + } + > + Ascending + Descending + +
+
+ {/*

{totalMembers}

*/} + + + + + + # + + + {t('Member Name')} + + + {t('Status')} + + + {t('Events Attended')} + + + {t('Task Assigned')} + + + + + {filteredAttendees.length === 0 ? ( + + + {t('noAttendees')} + + + ) : ( + filteredAttendees.map( + (member: InterfaceMember, index: number) => ( + + + {index + 1} + + + + {member.firstName} {member.lastName} + + + + {member.__typename === 'User' ? t('Member') : t('Admin')} + + ( + + ), + )} + > + + + {member.eventsAttended + ? member.eventsAttended.length + : /*istanbul ignore next*/ + '0'} + + + + + {member.tagsAssignedWith ? ( + /*istanbul ignore next*/ + member.tagsAssignedWith.edges.map( + /*istanbul ignore next*/ + ( + edge: { node: { name: string } }, + tagIndex: number, + ) =>
{edge.node.name}
, + ) + ) : ( +
None
+ )} +
+
+ ), + ) + )} +
+
+
+
+ ); +} + +export default EventAttendance; diff --git a/src/components/EventManagement/EventAttendance/EventStatistics.spec.tsx b/src/components/EventManagement/EventAttendance/EventStatistics.spec.tsx new file mode 100644 index 0000000000..38379b54fb --- /dev/null +++ b/src/components/EventManagement/EventAttendance/EventStatistics.spec.tsx @@ -0,0 +1,363 @@ +import React from 'react'; +import { act, render, screen, waitFor } from '@testing-library/react'; +import { AttendanceStatisticsModal } from './EventStatistics'; +import { MockedProvider } from '@apollo/client/testing'; +import { EVENT_DETAILS, RECURRING_EVENTS } from 'GraphQl/Queries/Queries'; +import userEvent from '@testing-library/user-event'; +import { exportToCSV } from 'utils/chartToPdf'; +import { vi, describe, expect, it } from 'vitest'; +import type { Mock } from 'vitest'; + +// Mock chart.js to avoid canvas errors +vi.mock('react-chartjs-2', async () => ({ + ...(await vi.importActual('react-chartjs-2')), + Line: () => null, + Bar: () => null, +})); +// Mock react-router-dom +vi.mock('react-router-dom', async () => ({ + ...(await vi.importActual('react-router-dom')), + useParams: () => ({ + orgId: 'org123', + eventId: 'event123', + }), +})); +vi.mock('utils/chartToPdf', async () => ({ + ...(await vi.importActual('utils/chartToPdf')), + exportToCSV: vi.fn(), +})); +const mocks = [ + { + request: { + query: EVENT_DETAILS, + variables: { id: 'event123' }, + }, + result: { + data: { + event: { + _id: 'event123', + title: 'Test Event', + description: 'Test Description', + startDate: '2023-01-01', + endDate: '2023-01-02', + startTime: '09:00', + endTime: '17:00', + allDay: false, + location: 'Test Location', + recurring: true, + baseRecurringEvent: { _id: 'base123' }, + organization: { + _id: 'org123', + members: [ + { _id: 'user1', firstName: 'John', lastName: 'Doe' }, + { _id: 'user2', firstName: 'Jane', lastName: 'Smith' }, + ], + }, + attendees: [ + { + _id: 'user1', + gender: 'MALE', + }, + { + _id: 'user2', + gender: 'FEMALE', + }, + ], + }, + }, + }, + }, + { + request: { + query: RECURRING_EVENTS, + variables: { baseRecurringEventId: 'base123' }, + }, + result: { + data: { + getRecurringEvents: [ + { + _id: 'event123', + startDate: '2023-01-01', + title: 'Test Event 1', + attendees: [ + { _id: 'user1', gender: 'MALE' }, + { _id: 'user2', gender: 'FEMALE' }, + ], + }, + { + _id: 'event456', + startDate: '2023-01-08', + title: 'Test Event 2', + attendees: [ + { _id: 'user1', gender: 'MALE' }, + { _id: 'user3', gender: 'OTHER' }, + ], + }, + { + _id: 'event789', + startDate: '2023-01-15', + title: 'Test Event 3', + attendees: [ + { _id: 'user2', gender: 'FEMALE' }, + { _id: 'user3', gender: 'OTHER' }, + ], + }, + ], + }, + }, + }, +]; + +const mockMemberData = [ + { + _id: 'user1', + firstName: 'John', + lastName: 'Doe', + gender: 'MALE', + birthDate: new Date('1990-01-01'), + email: 'john@example.com' as `${string}@${string}.${string}`, + createdAt: '2023-01-01', + __typename: 'User', + tagsAssignedWith: { + edges: [], + }, + }, + { + _id: 'user2', + firstName: 'Jane', + lastName: 'Smith', + gender: 'FEMALE', + birthDate: new Date('1985-05-05'), + email: 'jane@example.com' as `${string}@${string}.${string}`, + createdAt: '2023-01-01', + __typename: 'User', + tagsAssignedWith: { + edges: [], + }, + }, +]; + +const mockStatistics = { + totalMembers: 2, + membersAttended: 1, + attendanceRate: 50, +}; + +describe('AttendanceStatisticsModal', () => { + it('renders modal with correct initial state', async () => { + render( + + {}} + statistics={mockStatistics} + memberData={mockMemberData} + t={(key) => key} + /> + , + ); + + await waitFor(() => { + expect(screen.getByTestId('attendance-modal')).toBeInTheDocument(); + expect(screen.getByTestId('gender-button')).toBeInTheDocument(); + expect(screen.getByTestId('age-button')).toBeInTheDocument(); + }); + }); + + it('switches between gender and age demographics', async () => { + render( + + {}} + statistics={mockStatistics} + memberData={mockMemberData} + t={(key) => key} + /> + , + ); + + await waitFor(() => { + const genderButton = screen.getByTestId('gender-button'); + const ageButton = screen.getByTestId('age-button'); + + userEvent.click(ageButton); + expect(ageButton).toHaveClass('btn-success'); + expect(genderButton).toHaveClass('btn-light'); + + userEvent.click(genderButton); + expect(genderButton).toHaveClass('btn-success'); + expect(ageButton).toHaveClass('btn-light'); + }); + }); + + it('handles data demographics export functionality', async () => { + const mockExportToCSV = vi.fn(); + (exportToCSV as Mock).mockImplementation(mockExportToCSV); + + render( + + {}} + statistics={mockStatistics} + memberData={mockMemberData} + t={(key) => key} + /> + , + ); + + await waitFor(() => { + expect( + screen.getByRole('button', { name: 'Export Data' }), + ).toBeInTheDocument(); + }); + + await act(async () => { + const exportButton = screen.getByRole('button', { name: 'Export Data' }); + await userEvent.click(exportButton); + }); + + await act(async () => { + const demographicsExport = screen.getByTestId('demographics-export'); + await userEvent.click(demographicsExport); + }); + + expect(mockExportToCSV).toHaveBeenCalled(); + }); + it('handles data trends export functionality', async () => { + const mockExportToCSV = vi.fn(); + (exportToCSV as Mock).mockImplementation(mockExportToCSV); + + render( + + {}} + statistics={mockStatistics} + memberData={mockMemberData} + t={(key) => key} + /> + , + ); + + await waitFor(() => { + expect( + screen.getByRole('button', { name: 'Export Data' }), + ).toBeInTheDocument(); + }); + + await act(async () => { + const exportButton = screen.getByRole('button', { name: 'Export Data' }); + await userEvent.click(exportButton); + }); + + await act(async () => { + const demographicsExport = screen.getByTestId('trends-export'); + await userEvent.click(demographicsExport); + }); + + expect(mockExportToCSV).toHaveBeenCalled(); + }); + + it('displays recurring event data correctly', async () => { + render( + + {}} + statistics={mockStatistics} + memberData={mockMemberData} + t={(key) => key} + /> + , + ); + + await waitFor(() => { + expect(screen.getByTestId('today-button')).toBeInTheDocument(); + }); + }); + it('handles pagination and today button correctly', async () => { + render( + + {}} + statistics={mockStatistics} + memberData={mockMemberData} + t={(key) => key} + /> + , + ); + + // Wait for initial render + await waitFor(() => { + expect(screen.getByTestId('today-button')).toBeInTheDocument(); + }); + + // Test pagination + await act(async () => { + const nextButton = screen.getByAltText('right-arrow'); + await userEvent.click(nextButton); + }); + + await act(async () => { + const prevButton = screen.getByAltText('left-arrow'); + await userEvent.click(prevButton); + }); + + // Test today button + await act(async () => { + const todayButton = screen.getByTestId('today-button'); + await userEvent.click(todayButton); + }); + + // Verify buttons are present and interactive + expect(screen.getByAltText('right-arrow')).toBeInTheDocument(); + expect(screen.getByAltText('left-arrow')).toBeInTheDocument(); + expect(screen.getByTestId('today-button')).toBeInTheDocument(); + }); + + it('handles pagination in recurring events view', async () => { + render( + + {}} + statistics={mockStatistics} + memberData={mockMemberData} + t={(key) => key} + /> + , + ); + + await waitFor(() => { + const nextButton = screen.getByAltText('right-arrow'); + const prevButton = screen.getByAltText('left-arrow'); + + userEvent.click(nextButton); + userEvent.click(prevButton); + }); + }); + + it('closes modal correctly', async () => { + const handleClose = vi.fn(); + render( + + key} + /> + , + ); + + await waitFor(() => { + const closeButton = screen.getByTestId('close-button'); + userEvent.click(closeButton); + expect(handleClose).toHaveBeenCalled(); + }); + }); +}); diff --git a/src/components/EventManagement/EventAttendance/EventStatistics.tsx b/src/components/EventManagement/EventAttendance/EventStatistics.tsx new file mode 100644 index 0000000000..686ad049fa --- /dev/null +++ b/src/components/EventManagement/EventAttendance/EventStatistics.tsx @@ -0,0 +1,580 @@ +import React, { useEffect, useState, useMemo, useCallback } from 'react'; +import { + Modal, + Button, + ButtonGroup, + Tooltip, + OverlayTrigger, + Dropdown, +} from 'react-bootstrap'; +import 'react-datepicker/dist/react-datepicker.css'; +import { + Chart as ChartJS, + CategoryScale, + LinearScale, + PointElement, + LineElement, + BarElement, + Title, + Tooltip as ChartToolTip, + Legend, +} from 'chart.js'; +import { Bar, Line } from 'react-chartjs-2'; +import { useParams } from 'react-router-dom'; +import { EVENT_DETAILS, RECURRING_EVENTS } from 'GraphQl/Queries/Queries'; +import { useLazyQuery } from '@apollo/client'; +import { exportToCSV } from 'utils/chartToPdf'; +import type { ChartOptions, TooltipItem } from 'chart.js'; +import type { + InterfaceAttendanceStatisticsModalProps, + InterfaceEvent, + InterfaceRecurringEvent, +} from './InterfaceEvents'; +ChartJS.register( + CategoryScale, + LinearScale, + PointElement, + LineElement, + BarElement, + Title, + ChartToolTip, + Legend, +); +/** + * Component to display statistical information about event attendance + * Shows metrics like total attendees, filtering options, and attendance trends + * @returns JSX element with event statistics dashboard + */ + +export const AttendanceStatisticsModal: React.FC< + InterfaceAttendanceStatisticsModalProps +> = ({ show, handleClose, statistics, memberData, t }): JSX.Element => { + const [selectedCategory, setSelectedCategory] = useState('Gender'); + const { orgId, eventId } = useParams(); + const [currentPage, setCurrentPage] = useState(0); + const eventsPerPage = 10; + const [loadEventDetails, { data: eventData }] = useLazyQuery(EVENT_DETAILS); + const [loadRecurringEvents, { data: recurringData }] = + useLazyQuery(RECURRING_EVENTS); + const isEventRecurring = eventData?.event?.recurring; + const currentEventIndex = useMemo(() => { + if (!recurringData?.getRecurringEvents || !eventId) return -1; + return recurringData.getRecurringEvents.findIndex( + (event: InterfaceEvent) => event._id === eventId, + ); + }, [recurringData, eventId]); + useEffect(() => { + if (currentEventIndex >= 0) { + const newPage = Math.floor(currentEventIndex / eventsPerPage); + setCurrentPage(newPage); + } + }, [currentEventIndex, eventsPerPage]); + const filteredRecurringEvents = useMemo( + () => recurringData?.getRecurringEvents || [], + [recurringData], + ); + const totalEvents = filteredRecurringEvents.length; + const totalPages = Math.ceil(totalEvents / eventsPerPage); + + const paginatedRecurringEvents = useMemo(() => { + const startIndex = currentPage * eventsPerPage; + const endIndex = Math.min(startIndex + eventsPerPage, totalEvents); + return filteredRecurringEvents.slice(startIndex, endIndex); + }, [filteredRecurringEvents, currentPage, eventsPerPage, totalEvents]); + + const attendeeCounts = useMemo( + () => + paginatedRecurringEvents.map( + (event: InterfaceEvent) => event.attendees.length, + ), + [paginatedRecurringEvents], + ); + const chartOptions: ChartOptions<'line'> = { + responsive: true, + maintainAspectRatio: false, + animation: false, + scales: { y: { beginAtZero: true } }, + plugins: { + tooltip: { + callbacks: { + label: + /*istanbul ignore next*/ + (context: TooltipItem<'line'>) => { + const label = context.dataset.label || ''; + const value = context.parsed.y; + const isCurrentEvent = + paginatedRecurringEvents[context.dataIndex]._id === eventId; + return isCurrentEvent + ? `${label}: ${value} (Current Event)` + : `${label}: ${value}`; + }, + }, + }, + }, + }; + const eventLabels = useMemo( + () => + paginatedRecurringEvents.map((event: InterfaceEvent) => { + const date = (() => { + try { + const eventDate = new Date(event.startDate); + if (Number.isNaN(eventDate.getTime())) { + console.error(`Invalid date for event: ${event._id}`); + + return 'Invalid date'; + } + return eventDate.toLocaleDateString('en-US', { + month: 'short', + day: 'numeric', + }); + } catch (error) { + console.error( + `Error formatting date for event: ${event._id}`, + error, + ); + + return 'Invalid date'; + } + })(); + // Highlight the current event in the label + return event._id === eventId ? `→ ${date}` : date; + }), + [paginatedRecurringEvents, eventId], + ); + + const maleCounts = useMemo( + () => + paginatedRecurringEvents.map( + (event: InterfaceEvent) => + event.attendees.filter((attendee) => attendee.gender === 'MALE') + .length, + ), + [paginatedRecurringEvents], + ); + + const femaleCounts = useMemo( + () => + paginatedRecurringEvents.map( + (event: InterfaceEvent) => + event.attendees.filter((attendee) => attendee.gender === 'FEMALE') + .length, + ), + [paginatedRecurringEvents], + ); + + const otherCounts = useMemo( + () => + paginatedRecurringEvents.map( + (event: InterfaceEvent) => + event.attendees.filter( + (attendee) => + attendee.gender === 'OTHER' || attendee.gender === null, + ).length, + ), + [paginatedRecurringEvents], + ); + + const chartData = useMemo( + () => ({ + labels: eventLabels, + datasets: [ + { + label: 'Attendee Count', + data: attendeeCounts, + fill: true, + borderColor: '#008000', + pointRadius: paginatedRecurringEvents.map( + (event: InterfaceRecurringEvent) => (event._id === eventId ? 8 : 3), + ), + pointBackgroundColor: paginatedRecurringEvents.map( + (event: InterfaceRecurringEvent) => + event._id === eventId ? '#008000' : 'transparent', + ), + }, + { + label: 'Male Attendees', + data: maleCounts, + fill: false, + borderColor: '#0000FF', + }, + { + label: 'Female Attendees', + data: femaleCounts, + fill: false, + borderColor: '#FF1493', + }, + { + label: 'Other Attendees', + data: otherCounts, + fill: false, + borderColor: '#FFD700', + }, + ], + }), + [eventLabels, attendeeCounts, maleCounts, femaleCounts, otherCounts], + ); + + const handlePreviousPage = useCallback( + /*istanbul ignore next*/ + () => { + setCurrentPage((prevPage) => Math.max(prevPage - 1, 0)); + }, + [], + ); + + const handleNextPage = useCallback( + /*istanbul ignore next*/ + () => { + if (currentPage < totalPages - 1) { + setCurrentPage((prevPage) => prevPage + 1); + } + }, + [currentPage, totalPages], + ); + + const handleDateChange = useCallback((date: Date | null) => { + if (date) { + setCurrentPage(0); + } + }, []); + const categoryLabels = useMemo( + () => + selectedCategory === 'Gender' + ? ['Male', 'Female', 'Other'] + : ['Under 18', '18-40', 'Over 40'], + [selectedCategory], + ); + + const categoryData = useMemo( + () => + selectedCategory === 'Gender' + ? [ + memberData.filter((member) => member.gender === 'MALE').length, + memberData.filter((member) => member.gender === 'FEMALE').length, + memberData.filter( + (member) => + member.gender === 'OTHER' || + member.gender === null || + member.gender === '', + ).length, + ] + : [ + memberData.filter((member) => { + const today = new Date(); + const birthDate = new Date(member.birthDate); + let age = today.getFullYear() - birthDate.getFullYear(); + const monthDiff = today.getMonth() - birthDate.getMonth(); + if ( + monthDiff < 0 || + (monthDiff === 0 && today.getDate() < birthDate.getDate()) + ) { + /*istanbul ignore next*/ + age--; + } + return age < 18; + }).length, + memberData.filter((member) => { + const age = + new Date().getFullYear() - + new Date(member.birthDate).getFullYear(); + return age >= 18 && age <= 40; + }).length, + memberData.filter( + (member) => + new Date().getFullYear() - + new Date(member.birthDate).getFullYear() > + 40, + ).length, + ], + [selectedCategory, memberData], + ); + + const handleCategoryChange = useCallback((category: string): void => { + setSelectedCategory(category); + }, []); + + const exportTrendsToCSV = useCallback(() => { + const headers = [ + 'Date', + 'Attendee Count', + 'Male Attendees', + 'Female Attendees', + 'Other Attendees', + ]; + const data = [ + headers, + ...eventLabels.map((label: string, index: number) => [ + label, + attendeeCounts[index], + maleCounts[index], + femaleCounts[index], + otherCounts[index], + ]), + ]; + exportToCSV(data, 'attendance_trends.csv'); + }, [eventLabels, attendeeCounts, maleCounts, femaleCounts, otherCounts]); + + const exportDemographicsToCSV = useCallback(() => { + const headers = [selectedCategory, 'Count']; + const data = [ + headers, + ...categoryLabels.map((label, index) => [label, categoryData[index]]), + ]; + exportToCSV(data, `${selectedCategory.toLowerCase()}_demographics.csv`); + }, [selectedCategory, categoryLabels, categoryData]); + + const handleExport = (eventKey: string | null): void => { + switch (eventKey) { + case 'trends': + try { + exportTrendsToCSV(); + } catch (error) { + console.error('Failed to export trends:', error); + } + break; + case 'demographics': + try { + exportDemographicsToCSV(); + } catch (error) { + console.error('Failed to export demographics:', error); + } + break; + default: + return; + } + }; + useEffect(() => { + if (eventId) { + loadEventDetails({ variables: { id: eventId } }); + } + }, [eventId, loadEventDetails]); + useEffect(() => { + if (eventId && orgId && eventData?.event?.baseRecurringEvent?._id) { + loadRecurringEvents({ + variables: { + baseRecurringEventId: eventData?.event?.baseRecurringEvent?._id, + }, + }); + } + }, [eventId, orgId, eventData, loadRecurringEvents]); + return ( + + + + {t('historical_statistics')} + + + +
+
+ {isEventRecurring ? ( +
+ +
+

Trends

+
+
+ Previous Page} + > + + + + Next Page} + > + + +
+
+ ) : ( +
+

+ {statistics.totalMembers} +

+
+

Attendance Count

+
+
+ )} +
+ + + + + +
+

Demography

+
+
+
+
+ + + + Export Data + + + {isEventRecurring && ( + + Trends + + )} + + Demographics + + + + + +
+ ); +}; diff --git a/src/components/EventManagement/EventAttendance/InterfaceEvents.ts b/src/components/EventManagement/EventAttendance/InterfaceEvents.ts new file mode 100644 index 0000000000..7fc75ae4af --- /dev/null +++ b/src/components/EventManagement/EventAttendance/InterfaceEvents.ts @@ -0,0 +1,82 @@ +export interface InterfaceAttendanceStatisticsModalProps { + show: boolean; + handleClose: () => void; + statistics: { + totalMembers: number; + membersAttended: number; + attendanceRate: number; + }; + memberData: InterfaceMember[]; + t: (key: string) => string; +} + +export interface InterfaceMember { + createdAt: string; + firstName: string; + lastName: string; + email: `${string}@${string}.${string}`; + gender: string; + eventsAttended?: { + _id: string; + }[]; + birthDate: Date; + __typename: string; + _id: string; + tagsAssignedWith: { + edges: { + cursor: string; + node: { + name: string; + }; + }[]; + }; +} + +export interface InterfaceEvent { + _id: string; + title: string; + description: string; + startDate: string; + endDate: string; + location: string; + startTime: string; + endTime: string; + allDay: boolean; + recurring: boolean; + recurrenceRule: { + recurrenceStartDate: string; + recurrenceEndDate?: string | null; + frequency: string; + weekDays: string[]; + interval: number; + count?: number; + weekDayOccurenceInMonth?: number; + }; + isRecurringEventException: boolean; + isPublic: boolean; + isRegisterable: boolean; + attendees: { + _id: string; + firstName: string; + lastName: string; + email: string; + gender: string; + birthDate: string; + }[]; + __typename: string; +} + +export interface InterfaceRecurringEvent { + _id: string; + title: string; + startDate: string; + endDate: string; + frequency: InterfaceEvent['recurrenceRule']['frequency']; + interval: InterfaceEvent['recurrenceRule']['interval']; + attendees: { + _id: string; + gender: 'MALE' | 'FEMALE' | 'OTHER' | 'PREFER_NOT_TO_SAY'; + }[]; + isPublic: boolean; + isRegisterable: boolean; +} diff --git a/src/components/EventManagement/EventRegistrant/EventRegistrants.spec.tsx b/src/components/EventManagement/EventRegistrant/EventRegistrants.spec.tsx new file mode 100644 index 0000000000..828362706a --- /dev/null +++ b/src/components/EventManagement/EventRegistrant/EventRegistrants.spec.tsx @@ -0,0 +1,264 @@ +import React from 'react'; +import { MockedProvider } from '@apollo/react-testing'; +import type { RenderResult } from '@testing-library/react'; +import { render, screen, cleanup, waitFor } from '@testing-library/react'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; +import { I18nextProvider } from 'react-i18next'; +import EventRegistrants from './EventRegistrants'; +import { store } from 'state/store'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import i18n from 'utils/i18nForTest'; +import { REGISTRANTS_MOCKS } from './Registrations.mocks'; +import { MOCKS as ATTENDEES_MOCKS } from '../EventAttendance/Attendance.mocks'; +import { vi } from 'vitest'; +import { EVENT_REGISTRANTS, EVENT_ATTENDEES } from 'GraphQl/Queries/Queries'; + +const COMBINED_MOCKS = [...REGISTRANTS_MOCKS, ...ATTENDEES_MOCKS]; + +const link = new StaticMockLink(COMBINED_MOCKS, true); + +async function wait(): Promise { + await waitFor(() => { + return Promise.resolve(); + }); +} + +const renderEventRegistrants = (): RenderResult => { + return render( + + + + + + + + + , + ); +}; + +describe('Event Registrants Component', () => { + beforeEach(() => { + vi.mock('react-router-dom', async () => { + const actual = await vi.importActual('react-router-dom'); + return { + ...actual, + useParams: () => ({ eventId: 'event123', orgId: 'org123' }), + useNavigate: vi.fn(), + }; + }); + }); + + afterEach(() => { + vi.clearAllMocks(); + cleanup(); + }); + + test('Component loads correctly with table headers', async () => { + renderEventRegistrants(); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('table-header-serial')).toBeInTheDocument(); + expect(screen.getByTestId('table-header-registrant')).toBeInTheDocument(); + expect(screen.getByTestId('table-header-created-at')).toBeInTheDocument(); + expect( + screen.getByTestId('table-header-add-registrant'), + ).toBeInTheDocument(); + }); + }); + + test('Renders registrants button correctly', async () => { + renderEventRegistrants(); + + await waitFor(() => { + expect(screen.getByTestId('stats-modal')).toBeInTheDocument(); + expect(screen.getByTestId('filter-button')).toBeInTheDocument(); + }); + }); + + test('Handles empty registrants list', async () => { + const emptyMocks = [ + { + request: { + query: EVENT_REGISTRANTS, + variables: { eventId: '660fdf7d2c1ef6c7db1649ad' }, + }, + result: { + data: { + getEventAttendeesByEventId: [], + }, + }, + }, + { + request: { + query: EVENT_ATTENDEES, + variables: { id: '660fdf7d2c1ef6c7db1649ad' }, + }, + result: { + data: { + event: { + attendees: [], + }, + }, + }, + }, + ]; + + const customLink = new StaticMockLink(emptyMocks, true); + render( + + + + + + + + + , + ); + + await waitFor(() => { + expect(screen.getByTestId('no-registrants')).toBeInTheDocument(); + }); + }); + + test('Successfully combines and displays registrant and attendee data', async () => { + const mockData = [ + { + request: { + query: EVENT_REGISTRANTS, + variables: { eventId: 'event123' }, + }, + result: { + data: { + getEventAttendeesByEventId: [ + { + _id: '1', + userId: 'user1', + isRegistered: true, + __typename: 'EventAttendee', + }, + ], + }, + }, + }, + { + request: { + query: EVENT_ATTENDEES, + variables: { id: 'event123' }, + }, + result: { + data: { + event: { + attendees: [ + { + _id: 'user1', + firstName: 'John', + lastName: 'Doe', + createdAt: '2023-09-25T10:00:00.000Z', + __typename: 'User', + }, + ], + }, + }, + }, + }, + ]; + + const customLink = new StaticMockLink(mockData, true); + render( + + + + + + + + + , + ); + + await waitFor(() => { + expect(screen.getByTestId('registrant-row-0')).toBeInTheDocument(); + }); + + // Validate mapped data + expect(screen.getByTestId('attendee-name-0')).toHaveTextContent('John Doe'); + expect(screen.getByTestId('registrant-registered-at-0')).toHaveTextContent( + '2023-09-25', + ); + expect(screen.getByTestId('registrant-created-at-0')).toHaveTextContent( + '10:00:00', + ); + }); + + test('Handles missing attendee data with fallback values', async () => { + const mocksWithMissingFields = [ + { + request: { + query: EVENT_REGISTRANTS, + variables: { eventId: 'event123' }, + }, + result: { + data: { + getEventAttendeesByEventId: [ + { + _id: '1', + userId: 'user1', + isRegistered: true, + __typename: 'EventAttendee', + }, + ], + }, + }, + }, + { + request: { + query: EVENT_ATTENDEES, + variables: { id: 'event123' }, + }, + result: { + data: { + event: { + attendees: [ + { + _id: 'user1', + firstName: 'Jane', + lastName: 'Doe', + createdAt: null, + __typename: 'User', + }, + ], + }, + }, + }, + }, + ]; + + const customLink = new StaticMockLink(mocksWithMissingFields, true); + render( + + + + + + + + + , + ); + + await waitFor(() => { + expect(screen.getByTestId('registrant-row-0')).toBeInTheDocument(); + }); + + // Validate fallback values + expect(screen.getByTestId('attendee-name-0')).toHaveTextContent('Jane Doe'); + expect(screen.getByTestId('registrant-created-at-0')).toHaveTextContent( + 'N/A', + ); + }); +}); diff --git a/src/components/EventManagement/EventRegistrant/EventRegistrants.tsx b/src/components/EventManagement/EventRegistrant/EventRegistrants.tsx new file mode 100644 index 0000000000..efcc2e91f7 --- /dev/null +++ b/src/components/EventManagement/EventRegistrant/EventRegistrants.tsx @@ -0,0 +1,227 @@ +import React, { useEffect, useState, useCallback } from 'react'; +import { + Paper, + TableCell, + TableContainer, + TableHead, + TableRow, + TableBody, +} from '@mui/material'; +import { Button, Table } from 'react-bootstrap'; +import { useTranslation } from 'react-i18next'; +import style from '../../../style/app.module.css'; +import { useLazyQuery } from '@apollo/client'; +import { EVENT_ATTENDEES, EVENT_REGISTRANTS } from 'GraphQl/Queries/Queries'; +import { useParams } from 'react-router-dom'; +import type { InterfaceMember } from '../EventAttendance/InterfaceEvents'; +import { EventRegistrantsWrapper } from 'components/EventRegistrantsModal/EventRegistrantsWrapper'; +import { CheckInWrapper } from 'components/CheckIn/CheckInWrapper'; +/** + * Interface for user data + */ +interface InterfaceUser { + _id: string; + userId: string; + isRegistered: boolean; + __typename: string; + time: string; +} +/** + * Component to manage and display event registrant information + * Includes adding new registrants and check-in functionality for registrants + * @returns JSX element containing the event attendance interface + */ +function EventRegistrants(): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'eventRegistrant', + }); + const { orgId, eventId } = useParams<{ orgId: string; eventId: string }>(); + const [registrants, setRegistrants] = useState([]); + const [attendees, setAttendees] = useState([]); + const [combinedData, setCombinedData] = useState< + (InterfaceUser & Partial)[] + >([]); + // Fetch registrants + const [getEventRegistrants] = useLazyQuery(EVENT_REGISTRANTS, { + variables: { eventId }, + fetchPolicy: 'cache-and-network', + onCompleted: (data) => { + if (data?.getEventAttendeesByEventId) { + const mappedData = data.getEventAttendeesByEventId.map( + (attendee: InterfaceUser) => ({ + _id: attendee._id, + userId: attendee.userId, + isRegistered: attendee.isRegistered, + __typename: attendee.__typename, + }), + ); + setRegistrants(mappedData); + } + }, + }); + // Fetch attendees + const [getEventAttendees] = useLazyQuery(EVENT_ATTENDEES, { + variables: { id: eventId }, + fetchPolicy: 'cache-and-network', + onCompleted: (data) => { + if (data?.event?.attendees) { + setAttendees(data.event.attendees); + } + }, + }); + // callback function to refresh the data + const refreshData = useCallback(() => { + getEventRegistrants(); + getEventAttendees(); + }, [getEventRegistrants, getEventAttendees]); + useEffect(() => { + refreshData(); + }, [refreshData]); + // Combine registrants and attendees data + useEffect(() => { + if (registrants.length > 0 && attendees.length > 0) { + const mergedData = registrants.map((registrant) => { + const matchedAttendee = attendees.find( + (attendee) => attendee._id === registrant.userId, + ); + const [date, timeWithMilliseconds] = matchedAttendee?.createdAt + ? matchedAttendee.createdAt.split('T') + : ['N/A', 'N/A']; + const [time] = + timeWithMilliseconds !== 'N/A' + ? timeWithMilliseconds.split('.') + : ['N/A']; + return { + ...registrant, + firstName: matchedAttendee?.firstName || 'N/A', + lastName: matchedAttendee?.lastName || 'N/A', + createdAt: date, + time: time, + }; + }); + setCombinedData(mergedData); + } + }, [registrants, attendees]); + return ( +
+
+ {eventId ? ( + + ) : ( + + )} + +
+ + + + + + {t('serialNumber')} + + + {t('registrant')} + + + {t('registeredAt')} + + + {t('createdAt')} + + + {t('addRegistrant')} + + + + + {combinedData.length === 0 ? ( + + + {t('noRegistrantsFound')} + + + ) : ( + combinedData.map((data, index) => ( + + + {index + 1} + + + {data.firstName} {data.lastName} + + + {data.createdAt} + + + {data.time} + + + {eventId && orgId && ( + + )} + + + )) + )} + +
+
+
+ ); +} +export default EventRegistrants; diff --git a/src/components/EventManagement/EventRegistrant/Registrations.mocks.ts b/src/components/EventManagement/EventRegistrant/Registrations.mocks.ts new file mode 100644 index 0000000000..d71714459e --- /dev/null +++ b/src/components/EventManagement/EventRegistrant/Registrations.mocks.ts @@ -0,0 +1,67 @@ +import { EVENT_REGISTRANTS, EVENT_ATTENDEES } from 'GraphQl/Queries/Queries'; + +export const REGISTRANTS_MOCKS = [ + { + request: { + query: EVENT_REGISTRANTS, + variables: { eventId: '660fdf7d2c1ef6c7db1649ad' }, + }, + result: { + data: { + getEventAttendeesByEventId: [ + { + _id: '6589386a2caa9d8d69087484', + userId: '6589386a2caa9d8d69087484', + isRegistered: true, + __typename: 'EventAttendee', + }, + { + _id: '6589386a2caa9d8d69087485', + userId: '6589386a2caa9d8d69087485', + isRegistered: true, + __typename: 'EventAttendee', + }, + ], + }, + }, + }, + { + request: { + query: EVENT_ATTENDEES, + variables: { id: '660fdf7d2c1ef6c7db1649ad' }, + }, + result: { + data: { + event: { + attendees: [ + { + _id: '6589386a2caa9d8d69087484', + firstName: 'Bruce', + lastName: 'Garza', + createdAt: '2023-04-13T10:23:17.742Z', + __typename: 'User', + }, + { + _id: '6589386a2caa9d8d69087485', + firstName: 'Jane', + lastName: 'Smith', + createdAt: '2023-04-13T10:23:17.742Z', + __typename: 'User', + }, + ], + }, + }, + }, + }, +]; + +export const REGISTRANTS_MOCKS_ERROR = [ + { + // Error mock for EVENT_REGISTRANTS query + request: { + query: EVENT_REGISTRANTS, + variables: { eventId: 'event123' }, + }, + error: new Error('An error occurred while fetching registrants'), + }, +]; diff --git a/src/components/EventRegistrantsModal/AddOnSpotAttendee.spec.tsx b/src/components/EventRegistrantsModal/AddOnSpotAttendee.spec.tsx new file mode 100644 index 0000000000..66f0dda38b --- /dev/null +++ b/src/components/EventRegistrantsModal/AddOnSpotAttendee.spec.tsx @@ -0,0 +1,181 @@ +import React from 'react'; +import { render, fireEvent, screen, waitFor } from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import { BrowserRouter } from 'react-router-dom'; +import { SIGNUP_MUTATION } from 'GraphQl/Mutations/mutations'; +import AddOnSpotAttendee from './AddOnSpotAttendee'; +import userEvent from '@testing-library/user-event'; +import type { RenderResult } from '@testing-library/react'; +import { toast } from 'react-toastify'; +import { Provider } from 'react-redux'; +import { I18nextProvider } from 'react-i18next'; +import { store } from 'state/store'; +import i18nForTest from '../../utils/i18nForTest'; +import { describe, expect, vi } from 'vitest'; + +vi.mock('react-toastify', () => ({ + toast: { + success: vi.fn(), + error: vi.fn(), + }, +})); + +const mockProps = { + show: true, + handleClose: vi.fn(), + reloadMembers: vi.fn(), +}; +vi.mock('react-router-dom', async () => { + const actual = await vi.importActual('react-router-dom'); + return { + ...actual, + useParams: () => ({ eventId: '123', orgId: '123' }), + }; +}); + +const MOCKS = [ + { + request: { + query: SIGNUP_MUTATION, + variables: { + firstName: 'John', + lastName: 'Doe', + email: 'john@example.com', + phoneNo: '1234567890', + gender: 'Male', + password: '123456', + orgId: '123', + }, + }, + result: { + data: { + signUp: { + user: { + _id: '1', + }, + accessToken: 'mock-access-token', + refreshToken: 'mock-refresh-token', + }, + }, + }, + }, +]; + +const ERROR_MOCKS = [ + { + ...MOCKS[0], + error: new Error('Failed to add attendee'), + }, +]; + +const renderAddOnSpotAttendee = (): RenderResult => { + return render( + + + + + + + + + , + ); +}; + +describe('AddOnSpotAttendee Component', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('renders the component with all form fields', async () => { + renderAddOnSpotAttendee(); + + expect(screen.getByText('On-spot Attendee')).toBeInTheDocument(); + expect(screen.getByLabelText('First Name')).toBeInTheDocument(); + expect(screen.getByLabelText('Last Name')).toBeInTheDocument(); + expect(screen.getByLabelText('Email')).toBeInTheDocument(); + expect(screen.getByLabelText('Phone No.')).toBeInTheDocument(); + expect(screen.getByLabelText('Gender')).toBeInTheDocument(); + }); + + it('handles form input changes correctly', async () => { + renderAddOnSpotAttendee(); + + const firstNameInput = screen.getByLabelText('First Name'); + const lastNameInput = screen.getByLabelText('Last Name'); + const emailInput = screen.getByLabelText('Email'); + + userEvent.type(firstNameInput, 'John'); + userEvent.type(lastNameInput, 'Doe'); + userEvent.type(emailInput, 'john@example.com'); + + expect(firstNameInput).toHaveValue('John'); + expect(lastNameInput).toHaveValue('Doe'); + expect(emailInput).toHaveValue('john@example.com'); + }); + + it('submits form successfully and calls necessary callbacks', async () => { + renderAddOnSpotAttendee(); + + userEvent.type(screen.getByLabelText('First Name'), 'John'); + userEvent.type(screen.getByLabelText('Last Name'), 'Doe'); + userEvent.type(screen.getByLabelText('Email'), 'john@example.com'); + userEvent.type(screen.getByLabelText('Phone No.'), '1234567890'); + const genderSelect = screen.getByLabelText('Gender'); + fireEvent.change(genderSelect, { target: { value: 'Male' } }); + + fireEvent.submit(screen.getByTestId('onspot-attendee-form')); + await waitFor(() => { + expect(toast.success).toHaveBeenCalled(); + expect(mockProps.reloadMembers).toHaveBeenCalled(); + expect(mockProps.handleClose).toHaveBeenCalled(); + }); + }); + + it('displays error when organization ID is missing', async () => { + render( + + + + + , + ); + + fireEvent.submit(screen.getByTestId('onspot-attendee-form')); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalled(); + }); + }); + it('displays error when required fields are missing', async () => { + renderAddOnSpotAttendee(); + + fireEvent.submit(screen.getByTestId('onspot-attendee-form')); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalled(); + }); + }); + + it('handles mutation error appropriately', async () => { + render( + + + + + + + + + , + ); + + userEvent.type(screen.getByLabelText('First Name'), 'John'); + userEvent.type(screen.getByLabelText('Last Name'), 'Doe'); + fireEvent.submit(screen.getByTestId('onspot-attendee-form')); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalled(); + }); + }); +}); diff --git a/src/components/EventRegistrantsModal/AddOnSpotAttendee.tsx b/src/components/EventRegistrantsModal/AddOnSpotAttendee.tsx new file mode 100644 index 0000000000..6de839ce04 --- /dev/null +++ b/src/components/EventRegistrantsModal/AddOnSpotAttendee.tsx @@ -0,0 +1,209 @@ +import { SIGNUP_MUTATION } from 'GraphQl/Mutations/mutations'; +import React, { useState } from 'react'; +import { Modal, Form, Button, Spinner } from 'react-bootstrap'; +import { useParams } from 'react-router-dom'; +import { useMutation } from '@apollo/client'; +import { toast } from 'react-toastify'; +import 'react-toastify/dist/ReactToastify.css'; +import type { + InterfaceAddOnSpotAttendeeProps, + InterfaceFormData, +} from 'utils/interfaces'; +import { useTranslation } from 'react-i18next'; +import { errorHandler } from 'utils/errorHandler'; +/** + * Modal component for adding on-spot attendees to an event + * @param show - Boolean to control modal visibility + * @param handleClose - Function to handle modal close + * @param reloadMembers - Function to refresh member list after adding attendee + * @returns Modal component with form for adding new attendee + */ +const AddOnSpotAttendee: React.FC = ({ + show, + handleClose, + reloadMembers, +}) => { + const [formData, setFormData] = useState({ + firstName: '', + lastName: '', + email: '', + phoneNo: '', + gender: '', + }); + const { t } = useTranslation('translation', { keyPrefix: 'onSpotAttendee' }); + const { t: tCommon } = useTranslation('common'); + const { orgId } = useParams<{ orgId: string }>(); + const [isSubmitting, setIsSubmitting] = useState(false); + const [addSignUp] = useMutation(SIGNUP_MUTATION); + const validateForm = (): boolean => { + if (!formData.firstName || !formData.lastName || !formData.email) { + toast.error(t('invalidDetailsMessage')); + return false; + } + return true; + }; + + const resetForm = (): void => { + setFormData({ + firstName: '', + lastName: '', + email: '', + phoneNo: '', + gender: '', + }); + }; + + const handleChange = ( + e: React.ChangeEvent< + HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement + >, + ): void => { + const target = e.target as + | HTMLInputElement + | HTMLSelectElement + | HTMLTextAreaElement; + setFormData((prev) => ({ + ...prev, + [target.name]: target.value, + })); + }; + + const handleSubmit = async ( + e: React.FormEvent, + ): Promise => { + e.preventDefault(); + + if (!validateForm()) { + return; + } + + setIsSubmitting(true); + + try { + const response = await addSignUp({ + variables: { + ...formData, + password: '123456', + orgId, + }, + }); + + if (response.data?.signUp) { + toast.success(t('attendeeAddedSuccess')); + resetForm(); + reloadMembers(); + handleClose(); + } + } catch (error) { + /* istanbul ignore next */ + errorHandler(t, error as Error); + } finally { + setIsSubmitting(false); + } + }; + return ( + <> + + + {t('title')} + + +
+
+ + + {tCommon('firstName')} + + + + + + {tCommon('lastName')} + + + +
+ + {t('phoneNumber')} + + + + + {tCommon('email')} + + + + + {tCommon('gender')} + + + + + + + +
+ +
+
+
+ + ); +}; + +export default AddOnSpotAttendee; diff --git a/src/components/EventRegistrantsModal/EventRegistrantsModal.test.tsx b/src/components/EventRegistrantsModal/EventRegistrantsModal.spec.tsx similarity index 77% rename from src/components/EventRegistrantsModal/EventRegistrantsModal.test.tsx rename to src/components/EventRegistrantsModal/EventRegistrantsModal.spec.tsx index 8a084fef24..4f422ceb7f 100644 --- a/src/components/EventRegistrantsModal/EventRegistrantsModal.test.tsx +++ b/src/components/EventRegistrantsModal/EventRegistrantsModal.spec.tsx @@ -15,6 +15,7 @@ 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 { describe, test, expect, vi } from 'vitest'; const queryMockWithoutRegistrant = [ { @@ -41,7 +42,19 @@ const queryMockWithRegistrant = [ result: { data: { event: { - attendees: [{ _id: 'user1', firstName: 'John', lastName: 'Doe' }], + attendees: [ + { + _id: 'user1', + firstName: 'John', + lastName: 'Doe', + createdAt: '2023-01-01', + gender: 'Male', + birthDate: '1990-01-01', + eventsAttended: { + _id: 'event123', + }, + }, + ], }, }, }, @@ -64,9 +77,9 @@ const queryMockOrgMembers = [ _id: 'user1', firstName: 'John', lastName: 'Doe', - email: 'johndoe@palisadoes.com', - image: '', - createdAt: '12/12/22', + image: null, + email: 'johndoe@example.com', + createdAt: '2023-01-01', organizationsBlockedBy: [], }, ], @@ -76,6 +89,24 @@ const queryMockOrgMembers = [ }, }, ]; +const queryMockWithoutOrgMembers = [ + { + request: { + query: MEMBERS_LIST, + variables: { id: 'org123' }, + }, + result: { + data: { + organizations: [ + { + _id: 'org123', + members: [], + }, + ], + }, + }, + }, +]; const successfulAddRegistrantMock = [ { @@ -130,7 +161,7 @@ describe('Testing Event Registrants Modal', () => { show: true, eventId: 'event123', orgId: 'org123', - handleClose: jest.fn(), + handleClose: vi.fn(), }; test('The modal should be rendered, correct text must be displayed when there are no attendees and add attendee mutation must function properly', async () => { @@ -287,7 +318,7 @@ describe('Testing Event Registrants Modal', () => { }); test('Delete attendee mutation must fail properly', async () => { - const { queryByText, queryByTestId } = render( + const { queryByText, getByTestId } = render( { await waitFor(() => expect(queryByText('John Doe')).toBeInTheDocument()); - fireEvent.click(queryByTestId('CancelIcon') as Element); + const deleteButton = getByTestId('CancelIcon'); + fireEvent.click(deleteButton); await waitFor(() => expect(queryByText('Removing the attendee...')).toBeInTheDocument(), @@ -325,4 +357,48 @@ describe('Testing Event Registrants Modal', () => { expect(queryByText('Error removing attendee')).toBeInTheDocument(), ); }); + test('Autocomplete functionality works correctly', async () => { + const { getByTitle, getByText, getByPlaceholderText } = render( + + + + + + + + + + + + , + ); + + // Wait for loading state to finish + await waitFor(() => { + const autocomplete = getByPlaceholderText( + 'Choose the user that you want to add', + ); + expect(autocomplete).toBeInTheDocument(); + }); + + // Test empty state with no options + const autocomplete = getByPlaceholderText( + 'Choose the user that you want to add', + ); + fireEvent.change(autocomplete, { target: { value: 'NonexistentUser' } }); + + await waitFor(() => { + expect(getByText('No Registrations found')).toBeInTheDocument(); + expect(getByText('Add Onspot Registration')).toBeInTheDocument(); + }); + + // Test clicking "Add Onspot Registration" + fireEvent.click(getByText('Add Onspot Registration')); + expect(getByText('Add Onspot Registration')).toBeInTheDocument(); + const closeButton = getByTitle('Close'); + fireEvent.click(closeButton); + }); }); diff --git a/src/components/EventRegistrantsModal/EventRegistrantsModal.tsx b/src/components/EventRegistrantsModal/EventRegistrantsModal.tsx index bd2adc8a2c..d48d3b7439 100644 --- a/src/components/EventRegistrantsModal/EventRegistrantsModal.tsx +++ b/src/components/EventRegistrantsModal/EventRegistrantsModal.tsx @@ -14,6 +14,7 @@ import Stack from '@mui/material/Stack'; import TextField from '@mui/material/TextField'; import Autocomplete from '@mui/material/Autocomplete'; import { useTranslation } from 'react-i18next'; +import AddOnSpotAttendee from './AddOnSpotAttendee'; // Props for the EventRegistrantsModal component type ModalPropType = { @@ -43,6 +44,7 @@ interface InterfaceUser { export const EventRegistrantsModal = (props: ModalPropType): JSX.Element => { const { eventId, orgId, handleClose, show } = props; const [member, setMember] = useState(null); + const [open, setOpen] = useState(false); // Hooks for mutation operations const [addRegistrantMutation] = useMutation(ADD_EVENT_ATTENDEE); @@ -125,6 +127,19 @@ export const EventRegistrantsModal = (props: ModalPropType): JSX.Element => { return ( <> + setOpen(false) + } + reloadMembers={ + /*istanbul ignore next */ + () => { + attendeesRefetch(); + } + } + /> Event Registrants @@ -153,6 +168,19 @@ export const EventRegistrantsModal = (props: ModalPropType): JSX.Element => { onChange={(_, newMember): void => { setMember(newMember); }} + noOptionsText={ +
+

No Registrations found

+ { + setOpen(true); + }} + > + Add Onspot Registration + +
+ } options={memberData.organizations[0].members} getOptionLabel={(member: InterfaceUser): string => `${member.firstName} ${member.lastName}` @@ -160,6 +188,7 @@ export const EventRegistrantsModal = (props: ModalPropType): JSX.Element => { renderInput={(params): React.ReactNode => ( diff --git a/src/components/EventRegistrantsModal/EventRegistrantsWrapper.module.css b/src/components/EventRegistrantsModal/EventRegistrantsWrapper.module.css deleted file mode 100644 index 59b31333af..0000000000 --- a/src/components/EventRegistrantsModal/EventRegistrantsWrapper.module.css +++ /dev/null @@ -1,13 +0,0 @@ -button .iconWrapper { - width: 36px; - padding-right: 4px; - margin-right: 4px; - transform: translateY(4px); -} - -button .iconWrapperSm { - width: 36px; - display: flex; - justify-content: center; - align-items: center; -} diff --git a/src/components/EventRegistrantsModal/EventRegistrantsWrapper.test.tsx b/src/components/EventRegistrantsModal/EventRegistrantsWrapper.spec.tsx similarity index 95% rename from src/components/EventRegistrantsModal/EventRegistrantsWrapper.test.tsx rename to src/components/EventRegistrantsModal/EventRegistrantsWrapper.spec.tsx index d1707e8520..97a0d1f00f 100644 --- a/src/components/EventRegistrantsModal/EventRegistrantsWrapper.test.tsx +++ b/src/components/EventRegistrantsModal/EventRegistrantsWrapper.spec.tsx @@ -11,6 +11,7 @@ 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 { describe, test, expect } from 'vitest'; const queryMock = [ { @@ -77,7 +78,7 @@ describe('Testing Event Registrants Wrapper', () => { ); // Open the modal - fireEvent.click(queryByText('Show Registrants') as Element); + fireEvent.click(queryByText('Add Registrants') as Element); await waitFor(() => expect(queryByText('Event Registrants')).toBeInTheDocument(), diff --git a/src/components/EventRegistrantsModal/EventRegistrantsWrapper.tsx b/src/components/EventRegistrantsModal/EventRegistrantsWrapper.tsx index b198fcdd6d..36b6679a9f 100644 --- a/src/components/EventRegistrantsModal/EventRegistrantsWrapper.tsx +++ b/src/components/EventRegistrantsModal/EventRegistrantsWrapper.tsx @@ -1,13 +1,13 @@ import React, { useState } from 'react'; import { EventRegistrantsModal } from './EventRegistrantsModal'; import { Button } from 'react-bootstrap'; -import IconComponent from 'components/IconComponent/IconComponent'; -import styles from './EventRegistrantsWrapper.module.css'; +import style from '../../style/app.module.css'; // Props for the EventRegistrantsWrapper component type PropType = { eventId: string; orgId: string; + onUpdate?: () => void; }; /** @@ -20,37 +20,37 @@ type PropType = { export const EventRegistrantsWrapper = ({ eventId, orgId, + onUpdate, }: PropType): JSX.Element => { // State to control the visibility of the modal const [showModal, setShowModal] = useState(false); + const handleClose = (): void => { + setShowModal(false); + // Call onUpdate after modal is closed + if (onUpdate) { + onUpdate(); + } + }; return ( <> {/* Button to open the event registrants modal */} {/* Render the EventRegistrantsModal if showModal is true */} {showModal && ( { - setShowModal(false); // Hide the modal when closed - }} + handleClose={handleClose} eventId={eventId} orgId={orgId} /> diff --git a/src/components/GroupChatDetails/GroupChatDetails.module.css b/src/components/GroupChatDetails/GroupChatDetails.module.css new file mode 100644 index 0000000000..61119875f0 --- /dev/null +++ b/src/components/GroupChatDetails/GroupChatDetails.module.css @@ -0,0 +1,94 @@ +.groupInfo { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.memberList { + max-height: 300px; + overflow: scroll; +} + +.memberList::-webkit-scrollbar { + display: none; +} + +.listItem { + display: flex; + align-items: center; + gap: 10px; +} + +.groupMembersList { + display: flex; + align-items: center; + justify-content: space-between; +} + +.groupMembersList p { + margin: 0; + color: #959595; +} + +.membersImage { + width: 40px !important; +} + +.groupImage { + margin-bottom: 10px; +} + +.editImgBtn { + padding: 2px 6px 6px 8px; + border-radius: 100%; + background-color: white; + border: 1px solid #959595; + color: #959595; + outline: none; + position: relative; + top: -40px; + left: 40px; +} + +.chatImage { + height: 120px; + border-radius: 100%; + width: 120px; +} + +.editChatNameContainer { + display: flex; + gap: 15px; + align-items: center; + font-size: 20px; + margin-bottom: 10px; +} + +.editChatNameContainer input { + border: none; + border-bottom: 1px solid rgb(171, 171, 171); + outline: none; + padding: 0px 5px; +} + +.editChatNameContainer h3 { + margin: 0; +} + +.cancelIcon { + color: rgb(197, 42, 42); + cursor: pointer; + font-size: 16px; +} + +.checkIcon { + color: rgb(42, 197, 42); + cursor: pointer; +} + +.chatUserDetails { + display: flex; + gap: 10px; + align-items: center; +} diff --git a/src/components/GroupChatDetails/GroupChatDetails.test.tsx b/src/components/GroupChatDetails/GroupChatDetails.test.tsx new file mode 100644 index 0000000000..4a4aa73b61 --- /dev/null +++ b/src/components/GroupChatDetails/GroupChatDetails.test.tsx @@ -0,0 +1,603 @@ +import React from 'react'; +import { + render, + screen, + // fireEvent, + // waitFor, + act, + fireEvent, + waitFor, +} from '@testing-library/react'; +import GroupChatDetails from './GroupChatDetails'; +import { MockedProvider } from '@apollo/client/testing'; +import { + ADD_USER_TO_GROUP_CHAT, + UPDATE_CHAT, +} from 'GraphQl/Mutations/OrganizationMutations'; +import { USERS_CONNECTION_LIST } from 'GraphQl/Queries/Queries'; +import { I18nextProvider, initReactI18next } from 'react-i18next'; +import i18n from 'i18next'; +import { useLocalStorage } from 'utils/useLocalstorage'; + +const { setItem } = useLocalStorage(); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +i18n.use(initReactI18next).init({ + lng: 'en', + resources: { + en: { + translation: { + // Add your translations here + }, + }, + }, +}); + +const mockChat = { + _id: '1', + isGroup: true, + name: 'Test Group', + image: '', + messages: [], + admins: [ + { + _id: 'hbjguyt7y9890i9otyugttiyuh', + firstName: 'Admin', + lastName: 'User', + email: 'admin@example.com', + }, + ], + users: [ + { + _id: 'hbjguyt7y9890i9otyugttiyuh', + firstName: 'Admin', + lastName: 'User', + email: 'admin@example.com', + }, + { + _id: 'gjhnbbjku68979089ujhvserty', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + }, + ], + unseenMessagesByUsers: JSON.parse( + '{"hbjguyt7y9890i9otyugttiyuh": 0, "gjhnbbjku68979089ujhvserty": 0}', + ), + description: 'Test Description', +}; + +const mocks = [ + { + 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', + }, + ], + }, + }, + }, + { + request: { + query: ADD_USER_TO_GROUP_CHAT, + variables: { userId: '6589389d2caa9d8d69087487', chatId: '1' }, + }, + result: { + data: { + addUserToGroupChat: { + _id: '1', + success: true, + }, + }, + }, + }, + { + request: { + query: UPDATE_CHAT, + variables: { input: { _id: '1', image: '', name: 'New Group name' } }, + }, + result: { + data: { + updateChat: { + _id: '1', + success: true, + }, + }, + }, + }, + { + request: { + query: UPDATE_CHAT, + variables: {}, + }, + result: { + data: { + updateChat: { + _id: '1', + success: true, + }, + }, + }, + }, +]; + +describe('GroupChatDetails', () => { + it('renders correctly', async () => { + const chat = { + _id: '1', + isGroup: true, + name: 'Test Group', + image: '', + messages: [], + admins: [], + users: [], + unseenMessagesByUsers: JSON.parse( + '{"hbjguyt7y9890i9otyugttiyuh": 0, "gjhnbbjku68979089ujhvserty": 0}', + ), + description: 'Test Description', + }; + render( + + + + + , + ); + + await wait(); + + expect(screen.getByText('Test Group')).toBeInTheDocument(); + expect(screen.getByText('Test Description')).toBeInTheDocument(); + const closeButton = screen.getByRole('button', { name: /close/i }); + expect(closeButton).toBeInTheDocument(); + + fireEvent.click(closeButton); + }); + + it('edit chat title', async () => { + render( + + + + + , + ); + + await wait(); + await act(async () => { + fireEvent.click(await screen.findByTestId('editTitleBtn')); + }); + + await waitFor(async () => { + expect(await screen.findByTestId('chatNameInput')).toBeInTheDocument(); + }); + await act(async () => { + fireEvent.change(await screen.findByTestId('chatNameInput'), { + target: { value: 'New Group name' }, + }); + }); + + await act(async () => { + fireEvent.click(await screen.findByTestId('updateTitleBtn')); + }); + + await wait(); + + await waitFor( + async () => { + expect(await screen.findByTestId('editTitleBtn')).toBeInTheDocument(); + }, + { timeout: 5000 }, + ); + + await act(async () => { + fireEvent.click(await screen.findByTestId('editTitleBtn')); + }); + + await waitFor(async () => { + expect(await screen.findByTestId('cancelEditBtn')).toBeInTheDocument(); + }); + + act(() => { + fireEvent.click(screen.getByTestId('cancelEditBtn')); + }); + + await waitFor( + async () => { + expect(await screen.findByTestId('editTitleBtn')).toBeInTheDocument(); + }, + { timeout: 5000 }, + ); + }); + + it('add user to group chat', async () => { + setItem('userId', 'hbjguyt7y9890i9otyugttiyuh'); + render( + + + + + , + ); + + await wait(); + await act(async () => { + fireEvent.click(await screen.findByTestId('addMembers')); + }); + + await waitFor(async () => { + expect(await screen.findByTestId('searchUser')).toBeInTheDocument(); + }); + + await act(async () => { + fireEvent.change(await screen.findByTestId('searchUser'), { + target: { value: 'Disha' }, + }); + }); + + await act(async () => { + fireEvent.click(await screen.findByTestId('searchBtn')); + }); + + await wait(); + + await waitFor( + async () => { + expect(await screen.findByTestId('user')).toBeInTheDocument(); + }, + { timeout: 5000 }, + ); + + await act(async () => { + fireEvent.click(await screen.findByTestId('addUserBtn')); + }); + + await wait(10000); + }); + // test case for updating group chat image + it('update group chat image', async () => { + render( + + + + + , + ); + + await wait(); + + await waitFor( + async () => { + expect(await screen.findByTestId('editImageBtn')).toBeInTheDocument(); + }, + { timeout: 5000 }, + ); + + await act(async () => { + fireEvent.click(await screen.findByTestId('editImageBtn')); + }); + + const fileInput = screen.getByTestId('fileInput'); + const smallFile = new File(['small-file-content'], 'small-file.jpg'); // Small file + + Object.defineProperty(fileInput, 'files', { + value: [smallFile], + }); + + fireEvent.change(fileInput); + + await wait(10000); + }); +}); diff --git a/src/components/GroupChatDetails/GroupChatDetails.tsx b/src/components/GroupChatDetails/GroupChatDetails.tsx new file mode 100644 index 0000000000..e252a286be --- /dev/null +++ b/src/components/GroupChatDetails/GroupChatDetails.tsx @@ -0,0 +1,442 @@ +import { Paper, TableBody } from '@mui/material'; +import React, { useRef, useState } from 'react'; +import { Button, Form, ListGroup, Modal } from 'react-bootstrap'; +import styles from './GroupChatDetails.module.css'; +import type { ApolloQueryResult } from '@apollo/client'; +import { useMutation, useQuery } from '@apollo/client'; +import { + ADD_USER_TO_GROUP_CHAT, + UPDATE_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, Add } from '@mui/icons-material'; +import { useTranslation } from 'react-i18next'; +import Avatar from 'components/Avatar/Avatar'; +import { FiEdit } from 'react-icons/fi'; +import { FaCheck, FaX } from 'react-icons/fa6'; +import convertToBase64 from 'utils/convertToBase64'; +import useLocalStorage from 'utils/useLocalstorage'; + +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; + media: string; +}; + +type Chat = { + _id: string; + isGroup: boolean; + name?: string; + image?: string; + messages: DirectMessage[]; + admins: { + _id: string; + firstName: string; + lastName: string; + email: string; + }[]; + users: { + _id: string; + firstName: string; + lastName: string; + email: string; + }[]; + unseenMessagesByUsers: string; + description: string; +}; + +interface InterfaceGoroupChatDetailsProps { + toggleGroupChatDetailsModal: () => void; + groupChatDetailsModalisOpen: boolean; + chat: Chat; + chatRefetch: ( + variables?: + | Partial<{ + id: string; + }> + | undefined, + ) => Promise>; +} + +const StyledTableCell = styled(TableCell)(({ theme }) => ({ + [`&.${tableCellClasses.head}`]: { + backgroundColor: ['#31bb6b', '!important'], + color: theme.palette.common.white, + }, + [`&.${tableCellClasses.body}`]: { + fontSize: 14, + }, +})); + +const StyledTableRow = styled(TableRow)(() => ({ + '&:last-child td, &:last-child th': { + border: 0, + }, +})); + +/** + * Component for displaying and managing group chat details. + * + * @param props - The component props. + * @param toggleGroupChatDetailsModal - Function to toggle the group chat details modal. + * @param groupChatDetailsModalisOpen - Boolean indicating if the group chat details modal is open. + * @param chat - The chat object containing details about the group chat. + * @param chatRefetch - Function to refetch the chat data. + * @returns The rendered component. + */ +export default function groupChatDetails({ + toggleGroupChatDetailsModal, + groupChatDetailsModalisOpen, + chat, + chatRefetch, +}: InterfaceGoroupChatDetailsProps): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'userChat', + }); + + const [userName, setUserName] = useState(''); + const { getItem } = useLocalStorage(); + + const userId = getItem('userId'); + + const [editChatTitle, setEditChatTitle] = useState(false); + const [chatName, setChatName] = useState(chat?.name || ''); + + const [addUser] = useMutation(ADD_USER_TO_GROUP_CHAT); + + const [addUserModalisOpen, setAddUserModalisOpen] = useState(false); + + function openAddUserModal(): void { + setAddUserModalisOpen(true); + } + + const toggleAddUserModal = (): void => + setAddUserModalisOpen(!addUserModalisOpen); + + const { + data: allUsersData, + loading: allUsersLoading, + refetch: allUsersRefetch, + } = useQuery(USERS_CONNECTION_LIST, { + variables: { + firstName_contains: '', + lastName_contains: '', + }, + }); + + const addUserToGroupChat = async (userId: string): Promise => { + await addUser({ + variables: { + userId, + chatId: chat._id, + }, + }); + }; + + 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, + }); + }; + + const [selectedImage, setSelectedImage] = useState(''); + + const [updateChat] = useMutation(UPDATE_CHAT); + + const fileInputRef = useRef(null); + + const handleImageClick = (): void => { + fileInputRef?.current?.click(); + }; + + const handleImageChange = async ( + e: React.ChangeEvent, + ): Promise => { + const file = e.target.files?.[0]; + if (file) { + const base64 = await convertToBase64(file); + setSelectedImage(base64); + await updateChat(); + await chatRefetch(); + setSelectedImage(''); + } + }; + + return ( + <> + + + {t('groupInfo')} + + + +
+ {chat?.image ? ( + + ) : ( + + )} + + + {editChatTitle ? ( +
+ { + setChatName(e.target.value); + }} + /> + { + await updateChat({ + variables: { + input: { + _id: chat._id, + image: selectedImage ? selectedImage : '', + name: chatName, + }, + }, + }); + setEditChatTitle(false); + await chatRefetch(); + }} + /> + { + setEditChatTitle(false); + setChatName(chat.name || ''); + }} + /> +
+ ) : ( +
+

{chat?.name}

+ { + setEditChatTitle(true); + }} + /> +
+ )} + +

+ {chat?.users.length} {t('members')} +

+

{chat?.description}

+
+ +
+
+ {chat.users.length} {t('members')} +
+ + {chat.admins.map((admin) => admin._id).includes(userId) && ( + { + openAddUserModal(); + }} + > + {t('addMembers')} + + )} + {chat.users.map( + (user: { + _id: string; + firstName: string; + lastName: string; + }) => ( + +
+ + {user.firstName} {user.lastName} +
+ +
+ {chat.admins + .map((admin) => admin._id) + .includes(user._id) && ( +

Admin

+ )} +
+
+ ), + )} +
+
+
+
+ + + {'Chat'} + + + {allUsersLoading ? ( + <> + + + ) : ( + <> +
+
+ { + const { value } = e.target; + setUserName(value); + }} + /> + + +
+ + + + + + # + {'user'} + {'Chat'} + + + + {console.log(allUsersData)} + {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/IconComponent/IconComponent.test.tsx b/src/components/IconComponent/IconComponent.spec.tsx similarity index 90% rename from src/components/IconComponent/IconComponent.test.tsx rename to src/components/IconComponent/IconComponent.spec.tsx index 686a8e6f75..b398fe7986 100644 --- a/src/components/IconComponent/IconComponent.test.tsx +++ b/src/components/IconComponent/IconComponent.spec.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import IconComponent from './IconComponent'; +import { describe, it, expect } from 'vitest'; const screenTestIdMap: Record> = { MyOrganizations: { @@ -83,6 +84,14 @@ const screenTestIdMap: Record> = { name: 'My Pledges', testId: 'Icon-Component-My-Pledges', }, + LeaveOrganization: { + name: 'Leave Organization', + testId: 'Icon-Component-Leave-Organization', + }, + Volunteer: { + name: 'Volunteer', + testId: 'Icon-Component-Volunteer', + }, default: { name: 'default', testId: 'Icon-Component-DefaultIcon', diff --git a/src/components/IconComponent/IconComponent.tsx b/src/components/IconComponent/IconComponent.tsx index 4708dc7966..dd104c0408 100644 --- a/src/components/IconComponent/IconComponent.tsx +++ b/src/components/IconComponent/IconComponent.tsx @@ -19,6 +19,8 @@ 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 ExitToAppIcon from '@mui/icons-material/ExitToApp'; +import { MdOutlineVolunteerActivism } from 'react-icons/md'; import React from 'react'; @@ -133,6 +135,22 @@ const iconComponent = (props: InterfaceIconComponent): JSX.Element => { stroke={props.fill} /> ); + case 'Leave Organization': + return ( + + ); + case 'Volunteer': + return ( + + ); default: return ( { + test('Component should be rendered properly', () => { + render(); + + expect(screen.getByTestId('infiniteScrollLoader')).toBeInTheDocument(); + expect( + screen.getByTestId('infiniteScrollLoaderSpinner'), + ).toBeInTheDocument(); + }); +}); diff --git a/src/components/InfiniteScrollLoader/InfiniteScrollLoader.tsx b/src/components/InfiniteScrollLoader/InfiniteScrollLoader.tsx new file mode 100644 index 0000000000..7846889cdb --- /dev/null +++ b/src/components/InfiniteScrollLoader/InfiniteScrollLoader.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import styles from './InfiniteScrollLoader.module.css'; + +/** + * A Loader for infinite scroll. + */ + +const InfiniteScrollLoader = (): JSX.Element => { + return ( +
+
+
+ ); +}; + +export default InfiniteScrollLoader; diff --git a/src/components/LeftDrawer/LeftDrawer.module.css b/src/components/LeftDrawer/LeftDrawer.module.css deleted file mode 100644 index a9d330339f..0000000000 --- a/src/components/LeftDrawer/LeftDrawer.module.css +++ /dev/null @@ -1,239 +0,0 @@ -.leftDrawer { - width: calc(300px + 2rem); - position: fixed; - top: 0; - bottom: 0; - z-index: 100; - display: flex; - flex-direction: column; - padding: 1rem 1rem 0 1rem; - background-color: var(--bs-white); - transition: 0.5s; - font-family: var(--bs-leftDrawer-font-family); -} - -.activeDrawer { - width: calc(300px + 2rem); - position: fixed; - top: 0; - left: 0; - bottom: 0; - animation: comeToRightBigScreen 0.5s ease-in-out; -} - -.inactiveDrawer { - position: fixed; - top: 0; - left: calc(-300px - 2rem); - bottom: 0; - animation: goToLeftBigScreen 0.5s ease-in-out; -} - -.leftDrawer .talawaLogo { - width: 100%; - height: 65px; -} - -.leftDrawer .talawaText { - font-size: 20px; - text-align: center; - font-weight: 500; -} - -.leftDrawer .titleHeader { - margin: 2rem 0 1rem 0; - font-weight: 600; -} - -.leftDrawer .optionList button { - display: flex; - align-items: center; - width: 100%; - text-align: start; - margin-bottom: 0.8rem; - border-radius: 16px; - outline: none; - border: none; -} - -.leftDrawer .optionList button .iconWrapper { - width: 36px; -} - -.leftDrawer .profileContainer { - border: none; - width: 100%; - padding: 2.1rem 0.5rem; - height: 52px; - display: flex; - align-items: center; - background-color: var(--bs-white); -} - -.leftDrawer .profileContainer:focus { - outline: none; - background-color: var(--bs-gray-100); -} - -.leftDrawer .imageContainer { - width: 68px; -} - -.leftDrawer .profileContainer img { - height: 52px; - width: 52px; - border-radius: 50%; -} - -.leftDrawer .profileContainer .profileText { - flex: 1; - text-align: start; -} - -.leftDrawer .profileContainer .profileText .primaryText { - font-size: 1.1rem; - font-weight: 600; -} - -.leftDrawer .profileContainer .profileText .secondaryText { - font-size: 0.8rem; - font-weight: 400; - color: var(--bs-secondary); - display: block; - text-transform: capitalize; -} - -@media (max-width: 1120px) { - .leftDrawer { - width: calc(250px + 2rem); - padding: 1rem 1rem 0 1rem; - } -} - -/* For tablets */ -@media (max-width: 820px) { - .hideElemByDefault { - display: none; - } - - .leftDrawer { - width: 100%; - left: 0; - right: 0; - } - - .inactiveDrawer { - opacity: 0; - left: 0; - z-index: -1; - animation: closeDrawer 0.4s ease-in-out; - } - - .activeDrawer { - display: flex; - z-index: 100; - animation: openDrawer 0.6s ease-in-out; - } - - .logout { - margin-bottom: 2.5rem !important; - } -} - -@keyframes goToLeftBigScreen { - from { - left: 0; - } - - to { - opacity: 0.1; - left: calc(-300px - 2rem); - } -} - -/* Webkit prefix for older browser compatibility */ -@-webkit-keyframes goToLeftBigScreen { - from { - left: 0; - } - - to { - opacity: 0.1; - left: calc(-300px - 2rem); - } -} - -@keyframes comeToRightBigScreen { - from { - opacity: 0.4; - left: calc(-300px - 2rem); - } - - to { - opacity: 1; - left: 0; - } -} - -/* Webkit prefix for older browser compatibility */ -@-webkit-keyframes comeToRightBigScreen { - from { - opacity: 0.4; - left: calc(-300px - 2rem); - } - - to { - opacity: 1; - left: 0; - } -} - -@keyframes closeDrawer { - from { - left: 0; - opacity: 1; - } - - to { - left: -1000px; - opacity: 0; - } -} - -/* Webkit prefix for older browser compatibility */ -@-webkit-keyframes closeDrawer { - from { - left: 0; - opacity: 1; - } - - to { - left: -1000px; - opacity: 0; - } -} - -@keyframes openDrawer { - from { - opacity: 0; - left: -1000px; - } - - to { - left: 0; - opacity: 1; - } -} - -/* Webkit prefix for older browser compatibility */ -@-webkit-keyframes openDrawer { - from { - opacity: 0; - left: -1000px; - } - - to { - left: 0; - opacity: 1; - } -} diff --git a/src/components/LeftDrawer/LeftDrawer.test.tsx b/src/components/LeftDrawer/LeftDrawer.test.tsx index 6701d2d4bb..a4ad1cc47a 100644 --- a/src/components/LeftDrawer/LeftDrawer.test.tsx +++ b/src/components/LeftDrawer/LeftDrawer.test.tsx @@ -95,7 +95,7 @@ describe('Testing Left Drawer component for SUPERADMIN', () => { }); expect( - orgsBtn.className.includes('text-white btn btn-success'), + orgsBtn.className.includes('text-black btn btn-success'), ).toBeTruthy(); expect(rolesBtn.className.includes('text-secondary btn')).toBeTruthy(); expect( @@ -179,9 +179,7 @@ describe('Testing Left Drawer component for SUPERADMIN', () => { orgsBtn.click(); }); - expect( - orgsBtn.className.includes('text-white btn btn-success'), - ).toBeTruthy(); + expect(orgsBtn.className.includes('text-black')).toBeTruthy(); }); }); @@ -211,7 +209,7 @@ describe('Testing Left Drawer component for ADMIN', () => { }); expect( - orgsBtn.className.includes('text-white btn btn-success'), + orgsBtn.className.includes('text-black btn btn-success'), ).toBeTruthy(); // These screens aren't meant for admins, so they should not be present diff --git a/src/components/LeftDrawer/LeftDrawer.tsx b/src/components/LeftDrawer/LeftDrawer.tsx index 4628603ba1..eabf9722f8 100644 --- a/src/components/LeftDrawer/LeftDrawer.tsx +++ b/src/components/LeftDrawer/LeftDrawer.tsx @@ -6,7 +6,7 @@ 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 styles from 'style/app.module.css'; import useLocalStorage from 'utils/useLocalstorage'; export interface InterfaceLeftDrawerProps { @@ -63,17 +63,20 @@ const leftDrawer = ({ - + ) ) : ( {t('removeMemberMsg')} {/* Button to cancel the removal action */} - {/* Button to confirm the removal action */}
+ )) + )} +
+ +
+ + setTagSearchName(e.target.value.trim())} + data-testid="searchByName" + autoComplete="off" + /> +
+ +
+ {t('allTags')} +
+ {orgUserTagsLoading ? ( +
+ +
+ ) : ( + <> +
+ } + scrollableTarget="scrollableDiv" + > + {userTagsList?.map((tag) => ( +
+
+ +
+ + {/* Ancestor tags breadcrumbs positioned at the end of TagNode */} + {tag.parentTag && ( +
+ <>{'('} + {tag.ancestorTags?.map((ancestorTag) => ( + + {ancestorTag.name} + + + ))} + <>{')'} +
+ )} +
+ ))} +
+
+ + )} + + + + + + + + + + ); +}; + +export default TagActions; diff --git a/src/components/TagActions/TagActionsMocks.ts b/src/components/TagActions/TagActionsMocks.ts new file mode 100644 index 0000000000..f22458fa53 --- /dev/null +++ b/src/components/TagActions/TagActionsMocks.ts @@ -0,0 +1,706 @@ +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_DATA_CHUNK_SIZE } from 'utils/organizationTagsUtils'; + +export const MOCKS = [ + { + request: { + query: ORGANIZATION_USER_TAGS_LIST, + variables: { + id: '123', + first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { name: { starts_with: '' } }, + }, + }, + result: { + data: { + organizations: [ + { + userTags: { + edges: [ + { + node: { + _id: '1', + name: 'userTag 1', + parentTag: null, + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 11, + }, + ancestorTags: [], + }, + cursor: '1', + }, + { + node: { + _id: '2', + name: 'userTag 2', + parentTag: null, + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 0, + }, + ancestorTags: [], + }, + cursor: '2', + }, + { + node: { + _id: '3', + name: 'userTag 3', + parentTag: null, + usersAssignedTo: { + totalCount: 0, + }, + childTags: { + totalCount: 5, + }, + ancestorTags: [], + }, + cursor: '3', + }, + { + node: { + _id: '4', + name: 'userTag 4', + parentTag: null, + usersAssignedTo: { + totalCount: 0, + }, + childTags: { + totalCount: 0, + }, + ancestorTags: [], + }, + cursor: '4', + }, + { + node: { + _id: '5', + name: 'userTag 5', + parentTag: null, + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 5, + }, + ancestorTags: [], + }, + cursor: '5', + }, + { + node: { + _id: '6', + name: 'userTag 6', + parentTag: null, + usersAssignedTo: { + totalCount: 6, + }, + childTags: { + totalCount: 6, + }, + ancestorTags: [], + }, + cursor: '6', + }, + { + node: { + _id: '7', + name: 'userTag 7', + parentTag: null, + usersAssignedTo: { + totalCount: 7, + }, + childTags: { + totalCount: 7, + }, + ancestorTags: [], + }, + cursor: '7', + }, + { + node: { + _id: '8', + name: 'userTag 8', + parentTag: null, + usersAssignedTo: { + totalCount: 8, + }, + childTags: { + totalCount: 8, + }, + ancestorTags: [], + }, + cursor: '8', + }, + { + node: { + _id: '9', + name: 'userTag 9', + parentTag: null, + usersAssignedTo: { + totalCount: 9, + }, + childTags: { + totalCount: 9, + }, + ancestorTags: [], + }, + cursor: '9', + }, + { + node: { + _id: '10', + name: 'userTag 10', + parentTag: null, + usersAssignedTo: { + totalCount: 10, + }, + childTags: { + totalCount: 10, + }, + ancestorTags: [], + }, + 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_DATA_CHUNK_SIZE, + after: '10', + where: { name: { starts_with: '' } }, + }, + }, + result: { + data: { + organizations: [ + { + userTags: { + edges: [ + { + node: { + _id: '11', + name: 'userTag 11', + parentTag: null, + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 5, + }, + ancestorTags: [], + }, + cursor: '11', + }, + { + node: { + _id: '12', + name: 'userTag 12', + parentTag: null, + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 0, + }, + ancestorTags: [], + }, + cursor: '12', + }, + ], + pageInfo: { + startCursor: '11', + endCursor: '12', + hasNextPage: false, + hasPreviousPage: true, + }, + totalCount: 12, + }, + }, + ], + }, + }, + }, + { + request: { + query: ORGANIZATION_USER_TAGS_LIST, + variables: { + id: '123', + first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { name: { starts_with: 'searchUserTag' } }, + }, + }, + result: { + data: { + organizations: [ + { + userTags: { + edges: [ + { + node: { + _id: '1', + name: 'searchUserTag 1', + parentTag: { + _id: '1', + }, + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 5, + }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], + }, + cursor: '1', + }, + { + node: { + _id: '2', + name: 'searchUserTag 2', + parentTag: { + _id: '1', + }, + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 0, + }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], + }, + 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_DATA_CHUNK_SIZE, + }, + }, + result: { + data: { + getChildTags: { + name: 'userTag 1', + childTags: { + edges: [ + { + node: { + _id: 'subTag1', + name: 'subTag 1', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 5, + }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], + }, + cursor: 'subTag1', + }, + { + node: { + _id: 'subTag2', + name: 'subTag 2', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 0, + }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], + }, + cursor: 'subTag2', + }, + { + node: { + _id: 'subTag3', + name: 'subTag 3', + usersAssignedTo: { + totalCount: 0, + }, + childTags: { + totalCount: 5, + }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], + }, + cursor: 'subTag3', + }, + { + node: { + _id: 'subTag4', + name: 'subTag 4', + usersAssignedTo: { + totalCount: 0, + }, + childTags: { + totalCount: 0, + }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], + }, + cursor: 'subTag4', + }, + { + node: { + _id: 'subTag5', + name: 'subTag 5', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 5, + }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], + }, + cursor: 'subTag5', + }, + { + node: { + _id: 'subTag6', + name: 'subTag 6', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 5, + }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], + }, + cursor: 'subTag6', + }, + { + node: { + _id: 'subTag7', + name: 'subTag 7', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 5, + }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], + }, + cursor: 'subTag7', + }, + { + node: { + _id: 'subTag8', + name: 'subTag 8', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 5, + }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], + }, + cursor: 'subTag8', + }, + { + node: { + _id: 'subTag9', + name: 'subTag 9', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 5, + }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], + }, + cursor: 'subTag9', + }, + { + node: { + _id: 'subTag10', + name: 'subTag 10', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 5, + }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], + }, + cursor: 'subTag10', + }, + ], + pageInfo: { + startCursor: 'subTag1', + endCursor: 'subTag10', + hasNextPage: true, + hasPreviousPage: false, + }, + totalCount: 11, + }, + ancestorTags: [], + }, + }, + }, + }, + { + request: { + query: USER_TAG_SUB_TAGS, + variables: { + id: '1', + after: 'subTag10', + first: TAGS_QUERY_DATA_CHUNK_SIZE, + }, + }, + result: { + data: { + getChildTags: { + name: 'userTag 1', + childTags: { + edges: [ + { + node: { + _id: 'subTag11', + name: 'subTag 11', + usersAssignedTo: { + totalCount: 0, + }, + childTags: { + totalCount: 0, + }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], + }, + cursor: 'subTag11', + }, + ], + pageInfo: { + startCursor: 'subTag11', + endCursor: 'subTag11', + hasNextPage: false, + hasPreviousPage: true, + }, + totalCount: 11, + }, + ancestorTags: [], + }, + }, + }, + }, + { + 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_DATA_CHUNK_SIZE, + where: { name: { starts_with: '' } }, + }, + }, + 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_DATA_CHUNK_SIZE, + where: { name: { starts_with: '' } }, + }, + }, + result: { + data: { + organizations: [ + { + userTags: { + edges: [ + { + node: { + _id: '1', + name: 'userTag 1', + parentTag: null, + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 11, + }, + ancestorTags: [], + }, + cursor: '1', + }, + { + node: { + _id: '2', + name: 'userTag 2', + parentTag: null, + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 0, + }, + ancestorTags: [], + }, + 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_DATA_CHUNK_SIZE, + }, + }, + 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..4a085ecaf9 --- /dev/null +++ b/src/components/TagActions/TagNode.tsx @@ -0,0 +1,199 @@ +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 type { InterfaceOrganizationSubTagsQuery } from 'utils/organizationTagsUtils'; +import { TAGS_QUERY_DATA_CHUNK_SIZE } from 'utils/organizationTagsUtils'; +import styles from './TagActions.module.css'; +import InfiniteScroll from 'react-infinite-scroll-component'; +import InfiniteScrollLoader from 'components/InfiniteScrollLoader/InfiniteScrollLoader'; +import { WarningAmberRounded } from '@mui/icons-material'; +import type { TFunction } from 'i18next'; + +/** + * Props for the `TagNode` component. + */ +interface InterfaceTagNodeProps { + tag: InterfaceTagData; + checkedTags: Set; + toggleTagSelection: (tag: InterfaceTagData, isSelected: boolean) => void; + t: TFunction<'translation', 'manageTag'>; +} + +/** + * 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, + }: InterfaceOrganizationSubTagsQuery = useQuery(USER_TAG_SUB_TAGS, { + variables: { + id: tag._id, + first: TAGS_QUERY_DATA_CHUNK_SIZE, + }, + skip: !expanded, + }); + + const loadMoreSubTags = (): void => { + fetchMoreSubTags({ + variables: { + first: TAGS_QUERY_DATA_CHUNK_SIZE, + after: subTagsData?.getChildTags.childTags.pageInfo.endCursor, + }, + updateQuery: ( + prevResult: { getChildTags: InterfaceQueryUserTagChildTags }, + { + fetchMoreResult, + }: { + fetchMoreResult?: { getChildTags: InterfaceQueryUserTagChildTags }; + }, + ) => { + if (!fetchMoreResult) /* istanbul ignore next */ return prevResult; + + return { + getChildTags: { + ...fetchMoreResult.getChildTags, + childTags: { + ...fetchMoreResult.getChildTags.childTags, + edges: [ + ...prevResult.getChildTags.childTags.edges, + ...fetchMoreResult.getChildTags.childTags.edges, + ], + }, + }, + }; + }, + }); + }; + + if (subTagsError) { + return ( +
+
+ +
+ {t('errorOccurredWhileLoadingSubTags')} +
+
+
+ ); + } + + const subTagsList = + subTagsData?.getChildTags.childTags.edges.map((edge) => edge.node) ?? + /* istanbul ignore next */ []; + + const handleTagClick = (): void => { + setExpanded(!expanded); + }; + + const handleCheckboxChange = ( + e: React.ChangeEvent, + ): void => { + toggleTagSelection(tag, e.target.checked); + }; + + 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.test.tsx b/src/components/UpdateSession/UpdateSession.spec.tsx similarity index 81% rename from src/components/UpdateSession/UpdateSession.test.tsx rename to src/components/UpdateSession/UpdateSession.spec.tsx index ce0a868820..3453c990c2 100644 --- a/src/components/UpdateSession/UpdateSession.test.tsx +++ b/src/components/UpdateSession/UpdateSession.spec.tsx @@ -1,16 +1,7 @@ import React from 'react'; import { MockedProvider } from '@apollo/client/testing'; -import { - render, - screen, - act, - within, - fireEvent, - waitFor, -} from '@testing-library/react'; +import { render, screen, act, within } 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'; @@ -19,6 +10,18 @@ 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'; +import { vi } from 'vitest'; +/** + * This file contains unit tests for the `UpdateSession` component. + * + * The tests cover: + * - Proper rendering of the component with different scenarios, including mock data, null values, and error states. + * - Handling user interactions with the slider, such as setting minimum, maximum, and intermediate values. + * - Ensuring callbacks (e.g., `onValueChange`) are triggered correctly based on user input. + * - Simulating GraphQL query and mutation operations using mocked data to verify correct behavior in successful and error cases. + * - Testing edge cases, including null community data, invalid input values, and API errors, ensuring the component handles them gracefully. + * - Verifying proper integration of internationalization, routing, and toast notifications for success or error messages. + */ const MOCKS = [ { @@ -66,31 +69,29 @@ async function wait(ms = 100): Promise { }); } -jest.mock('react-toastify', () => ({ +vi.mock('react-toastify', () => ({ toast: { - success: jest.fn(), - warn: jest.fn(), - error: jest.fn(), + success: vi.fn(), + warn: vi.fn(), + error: vi.fn(), }, })); -jest.mock('utils/errorHandler', () => ({ - errorHandler: jest.fn(), +vi.mock('utils/errorHandler', () => ({ + errorHandler: vi.fn(), })); describe('Testing UpdateTimeout Component', () => { - let consoleWarnSpy: jest.SpyInstance; - beforeEach(() => { - consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation(); + vi.spyOn(console, 'warn').mockImplementation(() => {}); }); afterEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); }); - test('Should handle minimum slider value correctly', async () => { - const mockOnValueChange = jest.fn(); + it('Should handle minimum slider value correctly', async () => { + const mockOnValueChange = vi.fn(); render( @@ -109,8 +110,8 @@ describe('Testing UpdateTimeout Component', () => { expect(mockOnValueChange).toHaveBeenCalledWith(15); // Adjust based on slider min value }); - test('Should handle maximum slider value correctly', async () => { - const mockOnValueChange = jest.fn(); + it('Should handle maximum slider value correctly', async () => { + const mockOnValueChange = vi.fn(); render( @@ -129,8 +130,8 @@ describe('Testing UpdateTimeout Component', () => { 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(); + it('Should not update value if an invalid value is passed', async () => { + const mockOnValueChange = vi.fn(); render( @@ -150,8 +151,8 @@ describe('Testing UpdateTimeout Component', () => { expect(mockOnValueChange).not.toHaveBeenCalled(); }); - test('Should update slider value on user interaction', async () => { - const mockOnValueChange = jest.fn(); + it('Should update slider value on user interaction', async () => { + const mockOnValueChange = vi.fn(); render( @@ -169,7 +170,7 @@ describe('Testing UpdateTimeout Component', () => { expect(mockOnValueChange).toHaveBeenCalledWith(expect.any(Number)); // Adjust as needed }); - test('Components should render properly', async () => { + it('Components should render properly', async () => { render( @@ -203,7 +204,7 @@ describe('Testing UpdateTimeout Component', () => { expect(screen.getByRole('button', { name: /Update/i })).toBeInTheDocument(); }); - test('Should update session timeout', async () => { + it('Should update session timeout', async () => { render( @@ -228,7 +229,7 @@ describe('Testing UpdateTimeout Component', () => { ); }); - test('Should handle query errors', async () => { + it('Should handle query errors', async () => { const errorMocks = [ { request: { @@ -253,7 +254,7 @@ describe('Testing UpdateTimeout Component', () => { expect(errorHandler).toHaveBeenCalled(); }); - test('Should handle update errors', async () => { + it('Should handle update errors', async () => { const errorMocks = [ { request: { @@ -306,7 +307,7 @@ describe('Testing UpdateTimeout Component', () => { expect(errorHandler).toHaveBeenCalled(); }); - test('Should handle null community object gracefully', async () => { + it('Should handle null community object gracefully', async () => { render( diff --git a/src/components/UserListCard/UserListCard.test.tsx b/src/components/UserListCard/UserListCard.spec.tsx similarity index 77% rename from src/components/UserListCard/UserListCard.test.tsx rename to src/components/UserListCard/UserListCard.spec.tsx index e2ad552507..6a3b2d42d8 100644 --- a/src/components/UserListCard/UserListCard.test.tsx +++ b/src/components/UserListCard/UserListCard.spec.tsx @@ -1,5 +1,5 @@ -import React, { act } from 'react'; -import { render, screen } from '@testing-library/react'; +import React from 'react'; +import { render, screen, act } from '@testing-library/react'; import { MockedProvider } from '@apollo/react-testing'; import userEvent from '@testing-library/user-event'; import { I18nextProvider } from 'react-i18next'; @@ -9,6 +9,7 @@ import { ADD_ADMIN_MUTATION } from 'GraphQl/Mutations/mutations'; import i18nForTest from 'utils/i18nForTest'; import { BrowserRouter } from 'react-router-dom'; import { StaticMockLink } from 'utils/StaticMockLink'; +import { vi, describe, it, beforeEach } from 'vitest'; const MOCKS = [ { @@ -30,17 +31,15 @@ const MOCKS = [ const link = new StaticMockLink(MOCKS, true); async function wait(ms = 100): Promise { - await act(() => { - return new Promise((resolve) => { - setTimeout(resolve, ms); - }); - }); + await act(() => new Promise((resolve) => setTimeout(resolve, ms))); } describe('Testing User List Card', () => { - global.alert = jest.fn(); + beforeEach(() => { + vi.spyOn(global, 'alert').mockImplementation(() => {}); + }); - test('Should render props and text elements test for the page component', async () => { + it('Should render props and text elements test for the page component', async () => { const props = { id: '456', }; @@ -56,11 +55,10 @@ describe('Testing User List Card', () => { ); await wait(); - userEvent.click(screen.getByText(/Add Admin/i)); }); - test('Should render text elements when props value is not passed', async () => { + it('Should render text elements when props value is not passed', async () => { const props = { id: '456', }; diff --git a/src/components/UserPasswordUpdate/UserPasswordUpdate.test.tsx b/src/components/UserPasswordUpdate/UserPasswordUpdate.spec.tsx similarity index 58% rename from src/components/UserPasswordUpdate/UserPasswordUpdate.test.tsx rename to src/components/UserPasswordUpdate/UserPasswordUpdate.spec.tsx index 65f5e40f76..0d704eaed8 100644 --- a/src/components/UserPasswordUpdate/UserPasswordUpdate.test.tsx +++ b/src/components/UserPasswordUpdate/UserPasswordUpdate.spec.tsx @@ -1,43 +1,22 @@ import React, { act } from 'react'; -import { render, screen } from '@testing-library/react'; +import { render, screen, waitFor } from '@testing-library/react'; import { MockedProvider } from '@apollo/react-testing'; import userEvent from '@testing-library/user-event'; import { I18nextProvider } from 'react-i18next'; -import { UPDATE_USER_PASSWORD_MUTATION } from 'GraphQl/Mutations/mutations'; import i18nForTest from 'utils/i18nForTest'; import UserPasswordUpdate from './UserPasswordUpdate'; import { StaticMockLink } from 'utils/StaticMockLink'; import { toast as mockToast } from 'react-toastify'; +import { MOCKS } from './UserPasswordUpdateMocks'; +import { vi } from 'vitest'; -jest.mock('react-toastify', () => ({ +vi.mock('react-toastify', () => ({ toast: { - error: jest.fn(), - success: jest.fn(), + error: vi.fn(), + success: vi.fn(), }, })); -const MOCKS = [ - { - request: { - query: UPDATE_USER_PASSWORD_MUTATION, - variables: { - previousPassword: 'anshgoyal', - newPassword: 'anshgoyalansh', - confirmNewPassword: 'anshgoyalansh', - }, - }, - result: { - data: { - users: [ - { - _id: '1', - }, - ], - }, - }, - }, -]; - const link = new StaticMockLink(MOCKS, true); async function wait(ms = 5): Promise { @@ -56,9 +35,9 @@ describe('Testing User Password Update', () => { confirmNewPassword: 'ThePalisadoesFoundation', }; - global.alert = jest.fn(); + global.alert = vi.fn(); - test('should render props and text elements test for the page component', async () => { + it('should render props and text elements it for the page component', async () => { render( @@ -93,7 +72,7 @@ describe('Testing User Password Update', () => { ).toBeInTheDocument(); }); - test('displays an error when the password field is empty', async () => { + it('displays an error when the password field is empty', async () => { render( @@ -108,7 +87,7 @@ describe('Testing User Password Update', () => { expect(mockToast.error).toHaveBeenCalledWith(`Password can't be empty`); }); - test('displays an error when new and confirm password field does not match', async () => { + it('displays an error when new and confirm password field does not match', async () => { render( @@ -140,4 +119,67 @@ describe('Testing User Password Update', () => { 'New and Confirm password do not match.', ); }); + + it('Successfully update old password', async () => { + render( + + + + + , + ); + + await wait(); + + userEvent.type( + screen.getByPlaceholderText(/Previous Password/i), + formData.previousPassword, + ); + userEvent.type( + screen.getAllByPlaceholderText(/New Password/i)[0], + formData.newPassword, + ); + userEvent.type( + screen.getByPlaceholderText(/Confirm New Password/i), + formData.confirmNewPassword, + ); + + userEvent.click(screen.getByText(/Save Changes/i)); + expect(mockToast.success).toHaveBeenCalledWith( + 'Password updated Successfully', + ); + }); + + it('wrong old password', async () => { + render( + + + + + , + ); + + // await wait(); + + userEvent.type( + screen.getByPlaceholderText(/Previous Password/i), + formData.wrongPassword, + ); + userEvent.type( + screen.getAllByPlaceholderText(/New Password/i)[0], + formData.newPassword, + ); + userEvent.type( + screen.getByPlaceholderText(/Confirm New Password/i), + formData.confirmNewPassword, + ); + + userEvent.click(screen.getByText(/Save Changes/i)); + + await waitFor(() => + expect(mockToast.error).toHaveBeenCalledWith( + 'ApolloError: Invalid previous password', + ), + ); + }); }); diff --git a/src/components/UserPasswordUpdate/UserPasswordUpdateMocks.ts b/src/components/UserPasswordUpdate/UserPasswordUpdateMocks.ts new file mode 100644 index 0000000000..634286f590 --- /dev/null +++ b/src/components/UserPasswordUpdate/UserPasswordUpdateMocks.ts @@ -0,0 +1,40 @@ +import { UPDATE_USER_PASSWORD_MUTATION } from 'GraphQl/Mutations/mutations'; + +export const MOCKS = [ + { + request: { + query: UPDATE_USER_PASSWORD_MUTATION, + variables: { + previousPassword: 'Palisadoes', + newPassword: 'ThePalisadoesFoundation', + confirmNewPassword: 'ThePalisadoesFoundation', + }, + }, + result: { + data: { + users: [ + { + _id: '1', + }, + ], + }, + }, + }, + { + request: { + query: UPDATE_USER_PASSWORD_MUTATION, + variables: { + previousPassword: 'This is wrong password', + newPassword: 'ThePalisadoesFoundation', + confirmNewPassword: 'ThePalisadoesFoundation', + }, + }, + result: { + errors: [ + { + message: 'Invalid previous password', + }, + ], + }, + }, +]; diff --git a/src/components/UserPortal/ChatRoom/ChatRoom.module.css b/src/components/UserPortal/ChatRoom/ChatRoom.module.css index 5fc98351cd..5f89e6122a 100644 --- a/src/components/UserPortal/ChatRoom/ChatRoom.module.css +++ b/src/components/UserPortal/ChatRoom/ChatRoom.module.css @@ -4,8 +4,9 @@ /* background-color: rgba(196, 255, 211, 0.3); */ } -.backgroundWhite { +.sendMessageInput { background-color: white; + border-radius: 12px 0px 0px 12px; } .grey { @@ -152,7 +153,8 @@ } .contactImage { - height: fit-content; + height: 45px !important; + border-radius: 100%; } .senderInfo { @@ -235,6 +237,38 @@ animation-duration: 1s; } +.attachment { + padding: 10px; + background-color: rgb(219, 219, 219); + height: 200px; + display: flex; + align-items: flex-start; + border-radius: 10px; +} + +.attachment img { + height: 100%; + width: 100%; + object-fit: cover; + border-radius: 8px; +} + +.messageAttachment { + height: 300px; + width: 300px; + border-radius: 10px; + object-fit: cover; + margin: 10px 0px 10px 10px; +} + +.addAttachmentBtn { + border: none; + outline: none; + margin: 0 10px; + background-color: white; + font-size: 20px; +} + @keyframes test { from { background-color: white; diff --git a/src/components/UserPortal/ChatRoom/ChatRoom.spec.tsx b/src/components/UserPortal/ChatRoom/ChatRoom.spec.tsx new file mode 100644 index 0000000000..ef88baaf4c --- /dev/null +++ b/src/components/UserPortal/ChatRoom/ChatRoom.spec.tsx @@ -0,0 +1,5985 @@ +import React from 'react'; + +import { + act, + render, + screen, + fireEvent, + waitFor, +} from '@testing-library/react'; +import { MockedProvider, MockSubscriptionLink } 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, + GROUP_CHAT_LIST, + UNREAD_CHAT_LIST, +} from 'GraphQl/Queries/PlugInQueries'; +import { + MARK_CHAT_MESSAGES_AS_READ, + MESSAGE_SENT_TO_CHAT, + SEND_MESSAGE_TO_CHAT, +} from 'GraphQl/Mutations/OrganizationMutations'; +import ChatRoom from './ChatRoom'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import { vi } from 'vitest'; +import useLocalStorage from 'utils/useLocalstorage'; + +/** + * Unit tests for the ChatRoom component + * + * Tests cover component rendering, message functionality (sending/replying), + * user interactions, GraphQL integration, and provider integrations + * (Router, Redux, i18n) for both direct and group chats. + */ + +const { setItem } = useLocalStorage(); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +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 ', + media: null, + 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 ', + media: null, + 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: '8', + }, + }, + result: { + data: { + messageSentToChat: { + _id: '668ec1f1df364e03ac47a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + media: null, + 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 ', + media: null, + chatMessageBelongsTo: { + _id: '1', + }, + replyTo: null, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, +]; + +const UNREAD_CHAT_LIST_QUERY_MOCK = [ + { + request: { + query: UNREAD_CHAT_LIST, + variables: {}, + }, + result: { + data: { + getUnreadChatsByUserId: { + _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', + media: null, + 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: { + id: '8', + }, + }, + result: { + data: { + getUnreadChatsByUserId: { + _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', + media: null, + 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: { + id: '8', + }, + }, + result: { + data: { + getUnreadChatsByUserId: { + _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', + media: null, + 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: {}, + }, + result: { + data: { + getUnreadChatsByUserId: { + _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', + media: null, + 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: {}, + }, + result: { + data: { + getUnreadChatsByUserId: { + _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', + media: null, + 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: {}, + }, + result: { + data: { + getUnreadChatsByUserId: { + _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', + media: null, + 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + getUnreadChatsByUserId: { + _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', + media: null, + 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + getUnreadChatsByUserId: { + _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', + media: null, + 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + getUnreadChatsByUserId: { + _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', + media: null, + 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + getUnreadChatsByUserId: { + _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', + media: null, + 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + getUnreadChatsByUserId: { + _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', + media: null, + 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: { + id: '8', + }, + }, + result: { + data: { + getUnreadChatsByUserId: { + _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', + media: null, + 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: { + id: '8', + }, + }, + result: { + data: { + getUnreadChatsByUserId: { + _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', + media: null, + 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: { + id: '8', + }, + }, + result: { + data: { + getUnreadChatsByUserId: { + _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', + media: null, + 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + }, + }, + }, +]; + +const GROUP_CHAT_LIST_QUERY_MOCK = [ + { + request: { + query: GROUP_CHAT_LIST, + variables: { + id: '', + }, + }, + result: { + data: { + getGroupChatsByUserId: { + _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', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + }, + }, + }, + { + request: { + query: GROUP_CHAT_LIST, + variables: {}, + }, + result: { + data: { + getGroupChatsByUserId: { + _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', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + }, + }, + }, + { + request: { + query: GROUP_CHAT_LIST, + variables: {}, + }, + result: { + data: { + getGroupChatsByUserId: { + _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', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + }, + }, + }, + { + request: { + query: GROUP_CHAT_LIST, + variables: {}, + }, + result: { + data: { + getGroupChatsByUserId: { + _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', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + }, + }, + }, + { + request: { + query: GROUP_CHAT_LIST, + variables: {}, + }, + result: { + data: { + getGroupChatsByUserId: { + _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', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + }, + }, + }, + { + request: { + query: GROUP_CHAT_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + getGroupChatsByUserId: { + _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', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + }, + }, + }, + { + request: { + query: GROUP_CHAT_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + getGroupChatsByUserId: { + _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', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + }, + }, + }, + { + request: { + query: GROUP_CHAT_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + getGroupChatsByUserId: { + _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', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + }, + }, + }, +]; + +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', + media: null, + 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: { + '1': 0, + '2': 0, + }, + }, + }, + }, + }, + { + 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', + media: null, + 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: { + '1': 0, + '2': 0, + }, + }, + }, + }, + }, + { + 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', + media: null, + 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: { + '1': 0, + '2': 0, + }, + }, + }, + }, + }, +]; + +const CHATS_LIST_MOCK = [ + { + request: { + query: CHATS_LIST, + variables: { + id: '8', + }, + }, + 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', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: { + '1': 0, + '2': 0, + '3': 0, + '4': 0, + '5': 0, + }, + }, + { + _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', + media: null, + 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: '', + }, + ], + unseenMessagesByUsers: { + '1': 0, + '2': 0, + '3': 0, + '4': 0, + '5': 0, + }, + }, + ], + }, + }, + }, + { + request: { + query: CHATS_LIST, + variables: { + id: '8', + }, + }, + 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', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: { + '1': 0, + '2': 0, + '3': 0, + '4': 0, + '5': 0, + }, + }, + { + _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', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: { + '1': 0, + '2': 0, + '3': 0, + '4': 0, + '5': 0, + }, + }, + ], + }, + }, + }, + { + request: { + query: CHATS_LIST, + variables: { + id: '8', + }, + }, + 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', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: { + '1': 0, + '2': 0, + '3': 0, + '4': 0, + '5': 0, + }, + }, + { + _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', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: { + '1': 0, + '2': 0, + '3': 0, + '4': 0, + '5': 0, + }, + }, + ], + }, + }, + }, + { + 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', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: { + '1': 0, + '2': 0, + '3': 0, + '4': 0, + '5': 0, + }, + }, + { + _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', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: { + '1': 0, + '2': 0, + '3': 0, + '4': 0, + '5': 0, + }, + }, + ], + }, + }, + }, + { + 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', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: { + '1': 0, + '2': 0, + '3': 0, + '4': 0, + '5': 0, + }, + }, + { + _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', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: { + '1': 0, + '2': 0, + '3': 0, + '4': 0, + '5': 0, + }, + }, + ], + }, + }, + }, + { + 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', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: { + '1': 0, + '2': 0, + '3': 0, + '4': 0, + '5': 0, + }, + }, + { + _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', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: { + '1': 0, + '2': 0, + '3': 0, + '4': 0, + '5': 0, + }, + }, + ], + }, + }, + }, + { + 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', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: { + '1': 0, + '2': 0, + '3': 0, + '4': 0, + '5': 0, + }, + }, + { + _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', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: { + '1': 0, + '2': 0, + '3': 0, + '4': 0, + '5': 0, + }, + }, + ], + }, + }, + }, + { + 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', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: { + '1': 0, + '2': 0, + '3': 0, + '4': 0, + '5': 0, + }, + }, + { + _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', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: { + '1': 0, + '2': 0, + '3': 0, + '4': 0, + '5': 0, + }, + }, + ], + }, + }, + }, + { + request: { + query: CHATS_LIST, + variables: { + id: '2', + }, + }, + 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', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + '3': 0, + '4': 0, + '5': 0, + }), + }, + { + _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', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + '3': 0, + '4': 0, + '5': 0, + }), + }, + ], + }, + }, + }, + { + request: { + query: CHATS_LIST, + variables: { + id: '2', + }, + }, + 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', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: { + '1': 0, + '2': 0, + '3': 0, + '4': 0, + '5': 0, + }, + }, + { + _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', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: { + '1': 0, + '2': 0, + '3': 0, + '4': 0, + '5': 0, + }, + }, + ], + }, + }, + }, + { + request: { + query: CHATS_LIST, + variables: { + id: '2', + }, + }, + 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', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: { + '1': 0, + '2': 0, + '3': 0, + '4': 0, + '5': 0, + }, + }, + { + _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', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: { + '1': 0, + '2': 0, + '3': 0, + '4': 0, + '5': 0, + }, + }, + ], + }, + }, + }, + { + 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', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: { + '1': 0, + '2': 0, + '3': 0, + '4': 0, + '5': 0, + }, + }, + { + _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', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: { + '1': 0, + '2': 0, + '3': 0, + '4': 0, + '5': 0, + }, + }, + ], + }, + }, + }, + { + 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', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: { + '1': 0, + '2': 0, + '3': 0, + '4': 0, + '5': 0, + }, + }, + { + _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', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + '3': 0, + '4': 0, + '5': 0, + }), + }, + ], + }, + }, + }, +]; + +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', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + '3': 0, + '4': 0, + '5': 0, + }), + }, + }, + }, + }, + { + 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: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + '3': 0, + '4': 0, + '5': 0, + }), + }, + }, + }, + }, + { + 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: '345678', + createdAt: '345678908765', + messageContent: 'Hello', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + '3': 0, + '4': 0, + '5': 0, + }), + }, + }, + }, + }, + { + 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', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@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', + media: '', + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + }, + }, + }, + }, +]; + +const SEND_MESSAGE_TO_CHAT_MOCK = [ + { + request: { + query: SEND_MESSAGE_TO_CHAT, + variables: { + chatId: '1', + replyTo: '4', + messageContent: 'Test reply message', + media: 'https://test.com/image.jpg', + }, + }, + result: { + data: { + sendMessageToChat: { + _id: '668ec1f1364e03ac47a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + media: null, + 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', + media: '', + }, + }, + result: { + data: { + sendMessageToChat: { + _id: '668ec1f1364e03ac47a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + media: '', + 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 ', + media: null, + 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', + media: '', + }, + }, + result: { + data: { + sendMessageToChat: { + _id: '668ec1f1364e03ac47a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + media: null, + 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', + media: '', + }, + }, + result: { + data: { + sendMessageToChat: { + _id: '668ec1f1364e03ac47a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + media: null, + 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', + media: '', + }, + }, + result: { + data: { + sendMessageToChat: { + _id: '668ec1f1364e03ac47a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + media: null, + 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 reply message', + media: '', + }, + }, + result: { + data: { + sendMessageToChat: { + _id: '668ec1f1364e03ac47a151', + createdAt: '2024-07-10T17:16:33.248Z', + messageContent: 'Test ', + media: null, + replyTo: null, + sender: { + _id: '64378abd85008f171cf2990d', + firstName: 'Wilt', + lastName: 'Shepherd', + image: '', + }, + updatedAt: '2024-07-10', + }, + }, + }, + }, +]; + +const MARK_CHAT_MESSAGES_AS_READ_MOCK = [ + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: null, + chatId: '1', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: '8', + chatId: '1', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: '8', + chatId: '1', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: '8', + chatId: '1', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: '8', + chatId: '1', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: '8', + chatId: '1', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: '8', + chatId: '1', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: '8', + chatId: '1', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: '8', + chatId: '1', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: '8', + chatId: '1', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: '8', + chatId: '1', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: '8', + chatId: '1', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: '8', + chatId: '1', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: '8', + chatId: '1', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: null, + chatId: '1', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: null, + chatId: '1', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: null, + chatId: '1', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: null, + chatId: '', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: '2', + chatId: '1', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: '2', + chatId: '1', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: '2', + chatId: '1', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: null, + chatId: '', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: '1', + chatId: '', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: '1', + chatId: '', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: '1', + chatId: '', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, +]; + +describe('Testing Chatroom Component [User Portal]', () => { + window.HTMLElement.prototype.scrollIntoView = vi.fn(); + beforeEach(() => { + vi.clearAllMocks(); + vi.resetModules(); + }); + + it('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, + ...GROUP_CHAT_BY_ID_QUERY_MOCK, + ...SEND_MESSAGE_TO_CHAT_MOCK, + ...MARK_CHAT_MESSAGES_AS_READ_MOCK, + ...GROUP_CHAT_LIST_QUERY_MOCK, + ...UNREAD_CHAT_LIST_QUERY_MOCK, + ]; + render( + + + + + + + + + , + ); + await wait(); + expect(await screen.findByTestId('noChatSelected')).toBeInTheDocument(); + }); + + it('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, + ...GROUP_CHAT_BY_ID_QUERY_MOCK, + ...SEND_MESSAGE_TO_CHAT_MOCK, + ...MARK_CHAT_MESSAGES_AS_READ_MOCK, + ...GROUP_CHAT_LIST_QUERY_MOCK, + ...UNREAD_CHAT_LIST_QUERY_MOCK, + ]; + render( + + + + + + + + + , + ); + await wait(); + }); + + it('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, + ...MARK_CHAT_MESSAGES_AS_READ_MOCK, + ...GROUP_CHAT_LIST_QUERY_MOCK, + ...UNREAD_CHAT_LIST_QUERY_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); + }); + + 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); + }); + + it('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, + ...MARK_CHAT_MESSAGES_AS_READ_MOCK, + ...GROUP_CHAT_LIST_QUERY_MOCK, + ...UNREAD_CHAT_LIST_QUERY_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); + }); + + 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); + }); + + it('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, + ...MARK_CHAT_MESSAGES_AS_READ_MOCK, + ...GROUP_CHAT_LIST_QUERY_MOCK, + ...UNREAD_CHAT_LIST_QUERY_MOCK, + ]; + render( + + + + + + + + + , + ); + await wait(); + }); + + it('send message group chat', async () => { + 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, + ...MARK_CHAT_MESSAGES_AS_READ_MOCK, + ...GROUP_CHAT_LIST_QUERY_MOCK, + ...UNREAD_CHAT_LIST_QUERY_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); + }); + + 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); + }); + + act(() => { + fireEvent.change(input, { target: { value: 'Test reply message' } }); + }); + expect(input.value).toBe('Test reply message'); + + act(() => { + fireEvent.click(sendBtn); + }); + + await wait(500); + }); +}); diff --git a/src/components/UserPortal/ChatRoom/ChatRoom.test.tsx b/src/components/UserPortal/ChatRoom/ChatRoom.test.tsx deleted file mode 100644 index c808485132..0000000000 --- a/src/components/UserPortal/ChatRoom/ChatRoom.test.tsx +++ /dev/null @@ -1,1586 +0,0 @@ -import React from 'react'; - -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'; - -const { setItem } = useLocalStorage(); - -async function wait(ms = 100): Promise { - await act(() => { - return new Promise((resolve) => { - setTimeout(resolve, ms); - }); - }); -} - -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]', () => { - 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('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( - - - - - - - - - , - ); - await wait(); - }); - - 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( - - - - - - - - - , - ); - 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 c23244a314..fd06a47c12 100644 --- a/src/components/UserPortal/ChatRoom/ChatRoom.tsx +++ b/src/components/UserPortal/ChatRoom/ChatRoom.tsx @@ -5,18 +5,31 @@ 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 { CHAT_BY_ID, UNREAD_CHAT_LIST } from 'GraphQl/Queries/PlugInQueries'; +import type { ApolloQueryResult } from '@apollo/client'; import { useMutation, useQuery, useSubscription } from '@apollo/client'; import { + EDIT_CHAT_MESSAGE, + MARK_CHAT_MESSAGES_AS_READ, 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'; +import GroupChatDetails from 'components/GroupChatDetails/GroupChatDetails'; +import { GrAttachment } from 'react-icons/gr'; +import convertToBase64 from 'utils/convertToBase64'; interface InterfaceChatRoomProps { selectedContact: string; + chatListRefetch: ( + variables?: + | Partial<{ + id: string; + }> + | undefined, + ) => Promise>; } /** @@ -59,7 +72,7 @@ type DirectMessage = { } | undefined; messageContent: string; - type: string; + media: string; }; type Chat = { @@ -68,12 +81,20 @@ type Chat = { name?: string; image?: string; messages: DirectMessage[]; + admins: { + _id: string; + firstName: string; + lastName: string; + email: string; + }[]; users: { _id: string; firstName: string; lastName: string; email: string; }[]; + unseenMessagesByUsers: string; + description: string; }; export default function chatRoom(props: InterfaceChatRoomProps): JSX.Element { @@ -93,10 +114,23 @@ export default function chatRoom(props: InterfaceChatRoomProps): JSX.Element { const userId = getItem('userId'); const [chatTitle, setChatTitle] = useState(''); const [chatSubtitle, setChatSubtitle] = useState(''); + const [chatImage, setChatImage] = useState(''); const [newMessage, setNewMessage] = useState(''); const [chat, setChat] = useState(); const [replyToDirectMessage, setReplyToDirectMessage] = useState(null); + const [editMessage, setEditMessage] = useState(null); + const [groupChatDetailsModalisOpen, setGroupChatDetailsModalisOpen] = + useState(false); + + const [attachment, setAttachment] = useState(''); + + const openGroupChatDetails = (): void => { + setGroupChatDetailsModalisOpen(true); + }; + + const toggleGroupChatDetailsModal = (): void => + setGroupChatDetailsModalisOpen(!groupChatDetailsModalisOpen); /** * Handles changes to the new message input field. @@ -114,18 +148,49 @@ export default function chatRoom(props: InterfaceChatRoomProps): JSX.Element { variables: { chatId: props.selectedContact, replyTo: replyToDirectMessage?._id, + media: attachment, messageContent: newMessage, }, }); + const [editChatMessage] = useMutation(EDIT_CHAT_MESSAGE, { + variables: { + messageId: editMessage?._id, + messageContent: newMessage, + chatId: props.selectedContact, + }, + }); + + const [markChatMessagesAsRead] = useMutation(MARK_CHAT_MESSAGES_AS_READ, { + variables: { + chatId: props.selectedContact, + userId: userId, + }, + }); + const { data: chatData, refetch: chatRefetch } = useQuery(CHAT_BY_ID, { variables: { id: props.selectedContact, }, }); + // const { refetch: chatListRefetch } = useQuery(CHATS_LIST, { + // variables: { + // id: userId, + // }, + // }); + + const { refetch: unreadChatListRefetch } = useQuery(UNREAD_CHAT_LIST, { + variables: { + id: userId, + }, + }); + useEffect(() => { - chatRefetch(); + markChatMessagesAsRead().then(() => { + props.chatListRefetch(); + unreadChatListRefetch(); + }); }, [props.selectedContact]); useEffect(() => { @@ -135,6 +200,7 @@ export default function chatRoom(props: InterfaceChatRoomProps): JSX.Element { if (chat.isGroup) { setChatTitle(chat.name); setChatSubtitle(`${chat.users.length} members`); + setChatImage(chat.image); } else { const otherUser = chat.users.find( (user: { _id: string }) => user._id !== userId, @@ -142,35 +208,40 @@ export default function chatRoom(props: InterfaceChatRoomProps): JSX.Element { if (otherUser) { setChatTitle(`${otherUser.firstName} ${otherUser.lastName}`); setChatSubtitle(otherUser.email); + setChatImage(otherUser.image); } } } }, [chatData]); const sendMessage = async (): Promise => { - await sendMessageToChat(); + if (editMessage) { + await editChatMessage(); + } else { + await sendMessageToChat(); + } await chatRefetch(); setReplyToDirectMessage(null); setNewMessage(''); + setAttachment(''); + await props.chatListRefetch({ id: userId }); }; useSubscription(MESSAGE_SENT_TO_CHAT, { variables: { userId: userId, }, - onData: (messageSubscriptionData) => { + onData: async (messageSubscriptionData) => { if ( messageSubscriptionData?.data.data.messageSentToChat && messageSubscriptionData?.data.data.messageSentToChat .chatMessageBelongsTo['_id'] == props.selectedContact ) { + await markChatMessagesAsRead(); chatRefetch(); - } else { - chatRefetch({ - id: messageSubscriptionData?.data.data.messageSentToChat - .chatMessageBelongsTo['_id'], - }); } + props.chatListRefetch(); + unreadChatListRefetch(); }, }); @@ -180,6 +251,22 @@ export default function chatRoom(props: InterfaceChatRoomProps): JSX.Element { ?.lastElementChild?.scrollIntoView({ block: 'end' }); }); + const fileInputRef = useRef(null); + + const handleAddAttachment = (): void => { + fileInputRef?.current?.click(); + }; + + const handleImageChange = async ( + e: React.ChangeEvent, + ): Promise => { + const file = e.target.files?.[0]; + if (file) { + const base64 = await convertToBase64(file); + setAttachment(base64); + } + }; + return (
- -
+ {chatImage ? ( + {chatTitle} + ) : ( + + )} +
(chat?.isGroup ? openGroupChatDetails() : null)} + className={styles.userDetails} + >

{chatTitle}

{chatSubtitle}

@@ -274,6 +372,13 @@ export default function chatRoom(props: InterfaceChatRoomProps): JSX.Element {
)} + {message.media && ( + attachment + )} {message.messageContent}
@@ -294,7 +399,16 @@ export default function chatRoom(props: InterfaceChatRoomProps): JSX.Element { }} data-testid="replyBtn" > - Reply + {t('reply')} + + { + setEditMessage(message); + setNewMessage(message.messageContent); + }} + data-testid="replyToMessage" + > + Edit @@ -317,6 +431,13 @@ export default function chatRoom(props: InterfaceChatRoomProps): JSX.Element {
+ {!!replyToDirectMessage?._id && (
@@ -352,14 +473,33 @@ export default function chatRoom(props: InterfaceChatRoomProps): JSX.Element {
)} + {attachment && ( +
+ attachment + + +
+ )} + +
); } diff --git a/src/components/UserPortal/CommentCard/CommentCard.test.tsx b/src/components/UserPortal/CommentCard/CommentCard.spec.tsx similarity index 85% rename from src/components/UserPortal/CommentCard/CommentCard.test.tsx rename to src/components/UserPortal/CommentCard/CommentCard.spec.tsx index f02e5a606a..112fd1bcf5 100644 --- a/src/components/UserPortal/CommentCard/CommentCard.test.tsx +++ b/src/components/UserPortal/CommentCard/CommentCard.spec.tsx @@ -7,12 +7,23 @@ import { BrowserRouter } from 'react-router-dom'; import { store } from 'state/store'; import i18nForTest from 'utils/i18nForTest'; import { StaticMockLink } from 'utils/StaticMockLink'; - import CommentCard from './CommentCard'; import userEvent from '@testing-library/user-event'; import { LIKE_COMMENT, UNLIKE_COMMENT } from 'GraphQl/Mutations/mutations'; import useLocalStorage from 'utils/useLocalstorage'; - +import { vi } from 'vitest'; + +/** + * Unit tests for the CommentCard component. + * + * These tests ensure the CommentCard component renders and behaves as expected + * under different scenarios. They cover various functionalities like: + * - Initial rendering with comment liked/not liked by user + * - User liking a comment + * - User unliking a comment + * Mocked dependencies like `useLocalStorage` and Apollo Client mocks are used + * to isolate the component and test its behavior independently. + */ const { getItem, setItem } = useLocalStorage(); async function wait(ms = 100): Promise { @@ -56,8 +67,8 @@ const MOCKS = [ }, ]; -const handleLikeComment = jest.fn(); -const handleDislikeComment = jest.fn(); +const handleLikeComment = vi.fn(); +const handleDislikeComment = vi.fn(); const link = new StaticMockLink(MOCKS, true); describe('Testing CommentCard Component [User Portal]', () => { @@ -67,7 +78,7 @@ describe('Testing CommentCard Component [User Portal]', () => { }); }); - test('Component should be rendered properly if comment is already liked by the user.', async () => { + it('Component should be rendered properly if comment is already liked by the user.', async () => { const cardProps = { id: '1', creator: { @@ -108,7 +119,7 @@ describe('Testing CommentCard Component [User Portal]', () => { } }); - test('Component should be rendered properly if comment is not already liked by the user.', async () => { + it('Component should be rendered properly if comment is not already liked by the user.', async () => { const cardProps = { id: '1', creator: { @@ -149,7 +160,7 @@ describe('Testing CommentCard Component [User Portal]', () => { } }); - test('Component renders as expected if user likes the comment.', async () => { + it('Component renders as expected if user likes the comment.', async () => { const cardProps = { id: '1', creator: { @@ -195,7 +206,7 @@ describe('Testing CommentCard Component [User Portal]', () => { } }); - test('Component renders as expected if user unlikes the comment.', async () => { + it('Component renders as expected if user unlikes the comment.', async () => { const cardProps = { id: '1', creator: { diff --git a/src/components/UserPortal/ContactCard/ContactCard.module.css b/src/components/UserPortal/ContactCard/ContactCard.module.css index 19d66596c9..59d857efe2 100644 --- a/src/components/UserPortal/ContactCard/ContactCard.module.css +++ b/src/components/UserPortal/ContactCard/ContactCard.module.css @@ -10,8 +10,8 @@ .contactImage { width: 45px !important; - height: auto !important; - border-radius: 10px; + height: 45px !important; + border-radius: 100%; display: flex; align-items: center; justify-content: center; @@ -19,9 +19,10 @@ .contactNameContainer { display: flex; - flex-direction: column; padding: 0px 10px; - justify-content: center; + justify-content: space-between; + align-items: center; + flex-grow: 1; } .grey { @@ -35,3 +36,13 @@ .bgWhite { background-color: white; } + +.lastMessage { + margin-bottom: 0; + font-size: 14px; + color: rgba(163, 163, 163, 0.839); +} + +.unseenMessagesCount { + border-radius: 50%; +} diff --git a/src/components/UserPortal/ContactCard/ContactCard.test.tsx b/src/components/UserPortal/ContactCard/ContactCard.spec.tsx similarity index 72% rename from src/components/UserPortal/ContactCard/ContactCard.test.tsx rename to src/components/UserPortal/ContactCard/ContactCard.spec.tsx index 05a6a0a530..572a38feb7 100644 --- a/src/components/UserPortal/ContactCard/ContactCard.test.tsx +++ b/src/components/UserPortal/ContactCard/ContactCard.spec.tsx @@ -10,7 +10,19 @@ import i18nForTest from 'utils/i18nForTest'; import { StaticMockLink } from 'utils/StaticMockLink'; import ContactCard from './ContactCard'; import userEvent from '@testing-library/user-event'; - +import { vi } from 'vitest'; + +/** + * Unit tests for the ContactCard component. + * + * These tests ensure the ContactCard component renders and behaves as expected + * under different scenarios. They cover various functionalities like: + * - Rendering the contact card with and without a profile image + * - Selecting a contact by clicking on the card + * - Applying a grey background color to the selected contact card (for groups) + * Mocked dependencies like StaticMockLink are used + * to isolate the component and test its behavior independently. + */ const link = new StaticMockLink([], true); async function wait(ms = 100): Promise { @@ -30,12 +42,14 @@ let props = { image: '', selectedContact: '', type: '', - setSelectedContact: jest.fn(), - setSelectedChatType: jest.fn(), + unseenMessages: 2, + lastMessage: '', + setSelectedContact: vi.fn(), + setSelectedChatType: vi.fn(), }; describe('Testing ContactCard Component [User Portal]', () => { - test('Component should be rendered properly if person image is undefined', async () => { + it('Component should be rendered properly if person image is undefined', async () => { render( @@ -51,7 +65,7 @@ describe('Testing ContactCard Component [User Portal]', () => { await wait(); }); - test('Component should be rendered properly if person image is not undefined', async () => { + it('Component should be rendered properly if person image is not undefined', async () => { props = { ...props, image: 'personImage', @@ -72,7 +86,7 @@ describe('Testing ContactCard Component [User Portal]', () => { await wait(); }); - test('Contact gets selectected when component is clicked', async () => { + it('Contact gets selectected when component is clicked', async () => { render( @@ -92,7 +106,7 @@ describe('Testing ContactCard Component [User Portal]', () => { await wait(); }); - test('Component is rendered with background color grey if the contact is selected', async () => { + it('Component is rendered with background color grey if the contact is selected', async () => { props = { ...props, selectedContact: '1', diff --git a/src/components/UserPortal/ContactCard/ContactCard.tsx b/src/components/UserPortal/ContactCard/ContactCard.tsx index ef6bf2c9d5..5ec7c9c1d3 100644 --- a/src/components/UserPortal/ContactCard/ContactCard.tsx +++ b/src/components/UserPortal/ContactCard/ContactCard.tsx @@ -1,6 +1,7 @@ import React from 'react'; import styles from './ContactCard.module.css'; import Avatar from 'components/Avatar/Avatar'; +import { Badge } from 'react-bootstrap'; interface InterfaceContactCardProps { id: string; @@ -9,6 +10,8 @@ interface InterfaceContactCardProps { selectedContact: string; setSelectedContact: React.Dispatch>; isGroup: boolean; + unseenMessages: number; + lastMessage: string; } /** @@ -66,7 +69,15 @@ function contactCard(props: InterfaceContactCardProps): JSX.Element { /> )}
- {props.title} +
+ {props.title}{' '} +

{props.lastMessage}

+
+ {!!props.unseenMessages && ( + + {props.unseenMessages} + + )}
diff --git a/src/components/UserPortal/CreateDirectChat/CreateDirectChat.spec.tsx b/src/components/UserPortal/CreateDirectChat/CreateDirectChat.spec.tsx new file mode 100644 index 0000000000..ccf23a882b --- /dev/null +++ b/src/components/UserPortal/CreateDirectChat/CreateDirectChat.spec.tsx @@ -0,0 +1,4036 @@ +import React from 'react'; +import { + act, + fireEvent, + render, + screen, + waitFor, +} from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import { I18nextProvider } 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, + MARK_CHAT_MESSAGES_AS_READ, + MESSAGE_SENT_TO_CHAT, +} from 'GraphQl/Mutations/OrganizationMutations'; +import { + CHATS_LIST, + CHAT_BY_ID, + GROUP_CHAT_LIST, + UNREAD_CHAT_LIST, +} from 'GraphQl/Queries/PlugInQueries'; +import useLocalStorage from 'utils/useLocalstorage'; +import { vi } from 'vitest'; +const { setItem } = useLocalStorage(); + +/** + * Unit tests for the Create Direct Chat Modal functionality in the User Portal + * + * These tests cover the following scenarios: + * 1. Opening and closing the create new direct chat modal, ensuring proper UI elements + * like dropdown, search input, and submit button are displayed and functional. + * 2. Creating a new direct chat, which includes testing the interaction with the add button, + * submitting the chat, and closing the modal. + * + * Tests involve interacting with the modal's UI elements, performing actions like + * opening the dropdown, searching for users, clicking on the submit button, and closing + * the modal. GraphQL mocks are used for testing chat-related queries and mutations, + * ensuring that the modal behaves as expected when interacting with the GraphQL API. + */ + +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', + chatMessageBelongsTo: { + _id: '1', + }, + 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: { + messageSentToChat: { + _id: '668ec1f1df364e03ac47a151', + chatMessageBelongsTo: { + _id: '1', + }, + 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: { + messageSentToChat: { + _id: '668ec1f13603ac4697a151', + chatMessageBelongsTo: { + _id: '1', + }, + 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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + }, + }, + }, + { + 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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + }, + }, + }, + { + 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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + }, + }, + }, +]; + +const UNREAD_CHAT_LIST_QUERY_MOCK = [ + { + request: { + query: UNREAD_CHAT_LIST, + variables: {}, + }, + result: { + data: { + getUnreadChatsByUserId: { + _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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: {}, + }, + result: { + data: { + getUnreadChatsByUserId: { + _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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: {}, + }, + result: { + data: { + getUnreadChatsByUserId: { + _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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: {}, + }, + result: { + data: { + getUnreadChatsByUserId: { + _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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + getUnreadChatsByUserId: { + _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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + getUnreadChatsByUserId: { + _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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + getUnreadChatsByUserId: { + _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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + getUnreadChatsByUserId: { + _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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + getUnreadChatsByUserId: { + _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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + }, + }, + }, +]; + +const GROUP_CHAT_BY_USER_ID_QUERY_MOCK = [ + { + request: { + query: GROUP_CHAT_LIST, + variables: {}, + }, + result: { + data: { + getGroupChatsByUserId: { + _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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + }, + }, + }, + { + request: { + query: GROUP_CHAT_LIST, + variables: {}, + }, + result: { + data: { + getGroupChatsByUserId: { + _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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + }, + }, + }, + { + request: { + query: GROUP_CHAT_LIST, + variables: {}, + }, + result: { + data: { + getGroupChatsByUserId: { + _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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + }, + }, + }, +]; + +const CHATS_LIST_MOCK = [ + { + request: { + query: CHATS_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844efc814dd40fgh03db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + { + _id: '65844efc814ddgh4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: CHATS_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844efc814dd40fgh03db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + { + _id: '65844efc814ddgh4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: CHATS_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844efc814dd40fgh03db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + { + _id: '65844efc814ddgh4003db811c4', + isGroup: true, + image: null, + 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, + media: null, + type: 'STRING', + sender: { + _id: '2', + firstName: 'Test', + lastName: 'User', + email: 'test@example.com', + image: '', + }, + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@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: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: CHATS_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844efc814dd40fgh03db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + { + _id: '65844efc814ddgh4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: CHATS_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844efc814dd40fgh03db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + { + _id: '65844efc814ddgh4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: CHATS_LIST, + variables: { + id: '', + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844ghjefc814dd4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + { + _id: 'ujhgtrdtyuiop', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: CHATS_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844efc814dhjmkdftyd4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + { + _id: '65844ewsedrffc814dd4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: CHATS_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844efc814dhjmkdftyd4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + { + _id: '65844ewsedrffc814dd4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: CHATS_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844efc814dhjmkdftyd4003db811c4', + isGroup: true, + image: null, + 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', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + { + _id: '65844ewsedrffc814dd4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: CHATS_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844efc814dhjmkdftyd4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + { + _id: '65844ewsedrffc814dd4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: CHATS_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844efc814dhjmkdftyd4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + { + _id: '65844ewsedrffc814dd4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, +]; + +const GROUP_CHAT_BY_ID_QUERY_MOCK = [ + { + request: { + query: CHAT_BY_ID, + variables: { + id: '', + }, + }, + result: { + data: { + chatById: { + _id: '65844efc814dd4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + }, + }, + }, +]; + +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', + media: 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: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + }), + }, + }, + }, + }, +]; + +const MARK_CHAT_MESSAGES_AS_READ_MOCK = [ + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: null, + chatId: '', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: null, + chatId: '', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: null, + chatId: '', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: null, + chatId: '', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: '1', + chatId: '', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: '1', + chatId: '', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, +]; +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 = vi.fn(); + + Object.defineProperty(window, 'matchMedia', { + writable: true, + value: vi.fn().mockImplementation((query) => ({ + matches: false, + media: query, + onchange: null, + addListener: vi.fn(), // Deprecated + removeListener: vi.fn(), // Deprecated + addEventListener: vi.fn(), + removeEventListener: vi.fn(), + dispatchEvent: vi.fn(), + })), + }); + + it('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, + ...MARK_CHAT_MESSAGES_AS_READ_MOCK, + ...UNREAD_CHAT_LIST_QUERY_MOCK, + ...GROUP_CHAT_BY_USER_ID_QUERY_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); + }); + + it('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, + ...MARK_CHAT_MESSAGES_AS_READ_MOCK, + ...UNREAD_CHAT_LIST_QUERY_MOCK, + ...GROUP_CHAT_BY_USER_ID_QUERY_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.test.tsx b/src/components/UserPortal/CreateDirectChat/CreateDirectChat.test.tsx deleted file mode 100644 index e3e2eae75c..0000000000 --- a/src/components/UserPortal/CreateDirectChat/CreateDirectChat.test.tsx +++ /dev/null @@ -1,1496 +0,0 @@ -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 index e0ee9613c3..8125b6a463 100644 --- a/src/components/UserPortal/CreateDirectChat/CreateDirectChat.tsx +++ b/src/components/UserPortal/CreateDirectChat/CreateDirectChat.tsx @@ -5,10 +5,7 @@ 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 { 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'; @@ -19,8 +16,8 @@ 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'; +import { useTranslation } from 'react-i18next'; interface InterfaceCreateDirectChatProps { toggleCreateDirectChatModal: () => void; @@ -28,10 +25,10 @@ interface InterfaceCreateDirectChatProps { chatsListRefetch: ( variables?: | Partial<{ - id: any; + id: string; }> | undefined, - ) => Promise>; + ) => Promise>; } /** @@ -68,7 +65,6 @@ export default function createDirectChatModal({ const { t } = useTranslation('translation', { keyPrefix: 'userChat', }); - const { orgId: organizationId } = useParams(); const userId: string | null = getItem('userId'); @@ -195,7 +191,7 @@ export default function createDirectChatModal({ }} data-testid="addBtn" > - Add + {t('add')} diff --git a/src/components/UserPortal/CreateGroupChat/CreateGroupChat.module.css b/src/components/UserPortal/CreateGroupChat/CreateGroupChat.module.css index 3795e402fa..77fcfaf38f 100644 --- a/src/components/UserPortal/CreateGroupChat/CreateGroupChat.module.css +++ b/src/components/UserPortal/CreateGroupChat/CreateGroupChat.module.css @@ -7,3 +7,32 @@ .modalContent { width: 530px; } + +.groupInfo { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.groupImage { + margin-bottom: 10px; +} + +.editImgBtn { + padding: 2px 6px 6px 8px; + border-radius: 100%; + background-color: white; + border: 1px solid #959595; + color: #959595; + outline: none; + position: relative; + top: -40px; + left: 40px; +} + +.chatImage { + height: 120px; + border-radius: 100%; + width: 120px; +} diff --git a/src/components/UserPortal/CreateGroupChat/CreateGroupChat.spec.tsx b/src/components/UserPortal/CreateGroupChat/CreateGroupChat.spec.tsx new file mode 100644 index 0000000000..440273cbc4 --- /dev/null +++ b/src/components/UserPortal/CreateGroupChat/CreateGroupChat.spec.tsx @@ -0,0 +1,5801 @@ +import React from 'react'; +import { + act, + fireEvent, + render, + screen, + waitFor, +} 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, + MARK_CHAT_MESSAGES_AS_READ, + MESSAGE_SENT_TO_CHAT, +} from 'GraphQl/Mutations/OrganizationMutations'; +import { + CHATS_LIST, + CHAT_BY_ID, + GROUP_CHAT_LIST, + UNREAD_CHAT_LIST, +} from 'GraphQl/Queries/PlugInQueries'; +import useLocalStorage from 'utils/useLocalstorage'; +import { vi } from 'vitest'; + +/** + * Unit tests for the Create Group Chat Modal functionality in the User Portal + * + * These tests cover the following scenarios: + * 1. Opening and closing the create new group chat modal, ensuring proper UI elements + * like the dropdown, new group chat button, and close button are displayed and functional. + * 2. Creating a new group chat by interacting with the group name input field, organization + * selection, and submission process. It also ensures that the create button is properly + * triggered after filling out the required fields. + * 3. Adding and removing users from the group chat, testing the interactions with the add + * and remove buttons, and verifying the submit button and search functionality for user selection. + * + * GraphQL mocks are used to simulate chat-related queries and mutations. The tests ensure that + * the modal behaves correctly in various user interaction scenarios, including handling of form + * fields, user management, and modal navigation. + */ + +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', + chatMessageBelongsTo: { + _id: '1', + }, + 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: { + messageSentToChat: { + _id: '668ec1f1df364e03ac47a151', + chatMessageBelongsTo: { + _id: '1', + }, + 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: { + messageSentToChat: { + _id: '668ec1f13603ac4697a151', + chatMessageBelongsTo: { + _id: '1', + }, + 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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + }), + }, + }, + }, + }, + { + 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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + }), + }, + }, + }, + }, + { + 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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + }), + }, + }, + }, + }, +]; + +const UNREAD_CHAT_BY_USER_ID_QUERY_MOCK = [ + { + request: { + query: UNREAD_CHAT_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + getUnreadChatsByUserId: [ + { + _id: '65844efc814dd40hgjfgh03db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + getUnreadChatsByUserId: [ + { + _id: '65844efc814dd40hgjfgh03db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + getUnreadChatsByUserId: [ + { + _id: '65844efc814dd40hgjfgh03db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + getUnreadChatsByUserId: [ + { + _id: '65844efc814dd40hgjfgh03db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + getUnreadChatsByUserId: [ + { + _id: '65844efc814dd40hgjfgh03db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + getUnreadChatsByUserId: [ + { + _id: '65844efc814dd40hgjfgh03db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + getUnreadChatsByUserId: [ + { + _id: '65844efc814dd40hgjfgh03db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + getUnreadChatsByUserId: [ + { + _id: '65844efc814dd40hgjfgh03db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: {}, + }, + result: { + data: { + getUnreadChatsByUserId: [ + { + _id: '65844efc814dd40hgjfgh03db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: {}, + }, + result: { + data: { + getUnreadChatsByUserId: [ + { + _id: '65844efc814dd40hgjfgh03db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: {}, + }, + result: { + data: { + getUnreadChatsByUserId: [ + { + _id: '65844efc814dd40hgjfgh03db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: {}, + }, + result: { + data: { + getUnreadChatsByUserId: [ + { + _id: '65844efc814dd40hgjfgh03db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, +]; + +const CHATS_LIST_MOCK = [ + { + request: { + query: CHATS_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844efc814dd40hgjfgh03db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + { + _id: '65844efc814ddgh4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: CHATS_LIST, + variables: { + id: '', + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844ghjefc814dd4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + { + _id: '65844efc814ddgh4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: CHATS_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: 'fcfgcgchnbjhgfrftghj', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + { + _id: '65844efc814ddgh4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: CHATS_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844efc814dd40fgh03db8gjhbhn11c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + { + _id: '65844efc814ddgh4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: CHATS_LIST, + variables: { + id: '', + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844ghjefc814dd4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + { + _id: 'ujhgtrdtyuiop', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: CHATS_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844efc814dhjmkdftyd4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + { + _id: '65844ewsedrffc814dd4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, +]; + +const GROUP_CHAT_LIST_QUERY_MOCK = [ + { + request: { + query: GROUP_CHAT_LIST, + variables: { + id: '', + }, + }, + result: { + data: { + getGroupChatsByUserId: { + _id: '65844efc814dd4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + }, + }, + }, + { + request: { + query: GROUP_CHAT_LIST, + variables: {}, + }, + result: { + data: { + getGroupChatsByUserId: { + _id: '65844efc814dd4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + }, + }, + }, + { + request: { + query: GROUP_CHAT_LIST, + variables: {}, + }, + result: { + data: { + getGroupChatsByUserId: { + _id: '65844efc814dd4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + }, + }, + }, + { + request: { + query: GROUP_CHAT_LIST, + variables: {}, + }, + result: { + data: { + getGroupChatsByUserId: { + _id: '65844efc814dd4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + }, + }, + }, + { + request: { + query: GROUP_CHAT_LIST, + variables: {}, + }, + result: { + data: { + getGroupChatsByUserId: { + _id: '65844efc814dd4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + }, + }, + }, + { + request: { + query: GROUP_CHAT_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + getGroupChatsByUserId: { + _id: '65844efc814dd4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + }, + }, + }, + { + request: { + query: GROUP_CHAT_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + getGroupChatsByUserId: { + _id: '65844efc814dd4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + }, + }, + }, + { + request: { + query: GROUP_CHAT_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + getGroupChatsByUserId: { + _id: '65844efc814dd4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + }, + }, + }, +]; + +const GROUP_CHAT_BY_ID_QUERY_MOCK = [ + { + request: { + query: CHAT_BY_ID, + variables: { + id: '', + }, + }, + result: { + data: { + chatById: { + _id: '65844efc814dd4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + }, + }, + }, +]; + +const CREATE_CHAT_MUTATION = [ + { + request: { + query: CREATE_CHAT, + variables: { + organizationId: '6401ff65ce8e8406b8jygjgf07af2', + userIds: [null], + name: 'Test Group', + isGroup: true, + image: null, + }, + }, + result: { + data: { + createChat: { + _id: '65844efc814dd4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + }, + }, + }, + { + request: { + query: CREATE_CHAT, + variables: { + organizationId: '6401ff65ce8e8406b8jygjgf07af2', + userIds: [null], + name: 'Test Group', + isGroup: true, + image: null, + }, + }, + result: { + data: { + createChat: { + _id: '65844efc814dd4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + }, + }, + }, + { + request: { + query: CREATE_CHAT, + variables: { + organizationId: '6401ff65ce8e8406b8jygjgf07af2', + userIds: [null], + name: 'Test Group', + isGroup: true, + image: null, + }, + }, + result: { + data: { + createChat: { + _id: '65844efc814dd4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + }, + }, + }, + { + request: { + query: CREATE_CHAT, + variables: { + organizationId: '6401ff65ce8e8406b8jygjgf07af2', + userIds: [null], + name: 'Test Group', + isGroup: true, + image: null, + }, + }, + result: { + data: { + createChat: { + _id: '65844efc814dd4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + }, + }, + }, + { + request: { + query: CREATE_CHAT, + variables: { + userIds: [null], + name: 'Test Group', + isGroup: true, + image: null, + }, + }, + result: { + data: { + createChat: { + _id: '65844efc814dd4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + }, + }, + }, + { + request: { + query: CREATE_CHAT, + variables: { + userIds: [null], + name: 'Test Group', + isGroup: true, + image: null, + }, + }, + result: { + data: { + createChat: { + _id: '65844efc814dd4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + }, + }, + }, + { + request: { + query: CREATE_CHAT, + variables: { + userIds: [null], + name: 'Test Group', + isGroup: true, + image: null, + }, + }, + result: { + data: { + createChat: { + _id: '65844efc814dd4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + }, + }, + }, + { + request: { + query: CREATE_CHAT, + variables: { + userIds: [null], + name: 'Test Group', + isGroup: true, + image: null, + }, + }, + result: { + data: { + createChat: { + _id: '65844efc814dd4003db811c4', + isGroup: true, + image: null, + 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', + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + }, + }, + }, + { + request: { + query: CREATE_CHAT, + variables: { + organizationId: '', + userIds: [null], + name: 'Test Group', + isGroup: true, + image: null, + }, + }, + result: { + data: { + createChat: { + _id: '65844efc814dd4003db811c4', + isGroup: true, + image: null, + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + }, + }, + }, +]; + +const MARK_CHAT_MESSAGES_AS_READ_MOCK = [ + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: null, + chatId: '', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: null, + chatId: '', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: '1', + chatId: '', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: '1', + chatId: '', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: '1', + chatId: '', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, +]; + +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 = vi.fn(); + + Object.defineProperty(window, 'matchMedia', { + writable: true, + value: vi.fn().mockImplementation((query) => ({ + matches: false, + media: query, + onchange: null, + addListener: vi.fn(), // Deprecated + removeListener: vi.fn(), // Deprecated + addEventListener: vi.fn(), + removeEventListener: vi.fn(), + dispatchEvent: vi.fn(), + })), + }); + + it('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, + ...MARK_CHAT_MESSAGES_AS_READ_MOCK, + ...UNREAD_CHAT_BY_USER_ID_QUERY_MOCK, + ...GROUP_CHAT_LIST_QUERY_MOCK, + ]; + render( + + + + + + + + + , + ); + + await wait(); + + const dropdown = await screen.findByTestId('dropdown'); + expect(dropdown).toBeInTheDocument(); + fireEvent.click(dropdown); + const newGroupChatBtn = await screen.findByTestId('newDirectChat'); + expect(newGroupChatBtn).toBeInTheDocument(); + fireEvent.click(newGroupChatBtn); + + const closeButton = screen.getByRole('button', { name: /close/i }); + expect(closeButton).toBeInTheDocument(); + + fireEvent.click(closeButton); + }); + + it('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, + ...MARK_CHAT_MESSAGES_AS_READ_MOCK, + ...UNREAD_CHAT_BY_USER_ID_QUERY_MOCK, + ...GROUP_CHAT_LIST_QUERY_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 = (await screen.findByTestId( + 'groupTitleInput', + )) as unknown as HTMLInputElement; + + expect(groupTitleInput).toBeInTheDocument(); + + fireEvent.change(groupTitleInput, { target: { value: 'Test Group' } }); + await waitFor(() => { + expect(groupTitleInput.value).toBe('Test Group'); + }); + + 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); + + it('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, + ...MARK_CHAT_MESSAGES_AS_READ_MOCK, + ...UNREAD_CHAT_BY_USER_ID_QUERY_MOCK, + ...GROUP_CHAT_LIST_QUERY_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.test.tsx b/src/components/UserPortal/CreateGroupChat/CreateGroupChat.test.tsx deleted file mode 100644 index 7eeaeacac1..0000000000 --- a/src/components/UserPortal/CreateGroupChat/CreateGroupChat.test.tsx +++ /dev/null @@ -1,2455 +0,0 @@ -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 index 099a42310a..f61dcf620d 100644 --- a/src/components/UserPortal/CreateGroupChat/CreateGroupChat.tsx +++ b/src/components/UserPortal/CreateGroupChat/CreateGroupChat.tsx @@ -1,18 +1,9 @@ -import { - FormControl, - InputLabel, - MenuItem, - Paper, - Select, - TableBody, -} from '@mui/material'; -import type { SelectChangeEvent } from '@mui/material/Select'; -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useRef, useState } from 'react'; +import { Paper, TableBody } from '@mui/material'; 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'; @@ -26,6 +17,10 @@ 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'; +import convertToBase64 from 'utils/convertToBase64'; +import Avatar from 'components/Avatar/Avatar'; +import { FiEdit } from 'react-icons/fi'; interface InterfaceCreateGroupChatProps { toggleCreateGroupChatModal: () => void; @@ -36,31 +31,7 @@ interface InterfaceCreateGroupChatProps { 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; - }; - }[]; + ) => Promise>; } /** @@ -94,17 +65,15 @@ export default function CreateGroupChat({ createGroupChatModalisOpen, chatsListRefetch, }: InterfaceCreateGroupChatProps): JSX.Element { + const userId: string | null = getItem('userId'); 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 [description, setDescription] = useState(''); const [userIds, setUserIds] = useState([]); const [addUserModalisOpen, setAddUserModalisOpen] = useState(false); @@ -116,21 +85,11 @@ export default function CreateGroupChat({ 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 }, - }, - ); + const { orgId: currentOrg } = useParams(); function reset(): void { setTitle(''); setUserIds([]); - setSelectedOrganization(''); } useEffect(() => { @@ -140,10 +99,11 @@ export default function CreateGroupChat({ async function handleCreateGroupChat(): Promise { await createChat({ variables: { - organizationId: selectedOrganization, + organizationId: currentOrg, userIds: [userId, ...userIds], name: title, isGroup: true, + image: selectedImage, }, }); chatsListRefetch(); @@ -180,13 +140,23 @@ export default function CreateGroupChat({ }); }; - useEffect(() => { - if (joinedOrganizationsData && joinedOrganizationsData.users.length > 0) { - const organizations = - joinedOrganizationsData.users[0]?.user?.joinedOrganizations || []; - setOrganizations(organizations); + const [selectedImage, setSelectedImage] = useState(null); + + const fileInputRef = useRef(null); + + const handleImageClick = (): void => { + fileInputRef?.current?.click(); + }; + + const handleImageChange = async ( + e: React.ChangeEvent, + ): Promise => { + const file = e.target.files?.[0]; + if (file) { + const base64 = await convertToBase64(file); + setSelectedImage(base64); } - }, [joinedOrganizationsData]); + }; return ( <> @@ -200,66 +170,57 @@ export default function CreateGroupChat({ New Group + +
+ {selectedImage ? ( + + ) : ( + + )} + +
- {/* - Select Organization - - */} - - Select Organization - - - Group name + Title { setTitle(e.target.value); }} /> + + Description + { + setDescription(e.target.value); + }} + /> + )} @@ -385,7 +346,7 @@ export default function CreateGroupChat({ onClick={handleCreateGroupChat} data-testid="createBtn" > - Create + {t('create')} diff --git a/src/components/UserPortal/DonationCard/DonationCard.test.tsx b/src/components/UserPortal/DonationCard/DonationCard.spec.tsx similarity index 64% rename from src/components/UserPortal/DonationCard/DonationCard.test.tsx rename to src/components/UserPortal/DonationCard/DonationCard.spec.tsx index cddf62dd6c..f4d8473dd1 100644 --- a/src/components/UserPortal/DonationCard/DonationCard.test.tsx +++ b/src/components/UserPortal/DonationCard/DonationCard.spec.tsx @@ -11,6 +11,19 @@ import { StaticMockLink } from 'utils/StaticMockLink'; import DonationCard from './DonationCard'; import { type InterfaceDonationCardProps } from 'screens/UserPortal/Donate/Donate'; +/** + * Unit test for the DonationCard component in the User Portal + * + * This test ensures that the DonationCard component renders correctly when provided with + * the required props. It uses the MockedProvider to mock any GraphQL queries and the + * StaticMockLink to simulate the network layer. The component is wrapped with necessary + * providers such as BrowserRouter, Redux store, and i18n provider to simulate the environment + * in which the component operates. + * + * The test specifically checks if the component renders without errors, though more tests + * can be added in the future to validate interactions and state changes based on user actions. + */ + const link = new StaticMockLink([], true); async function wait(ms = 100): Promise { @@ -31,7 +44,7 @@ const props: InterfaceDonationCardProps = { }; describe('Testing ContactCard Component [User Portal]', () => { - test('Component should be rendered properly', async () => { + it('Component should be rendered properly', async () => { render( diff --git a/src/components/UserPortal/EventCard/EventCard.test.tsx b/src/components/UserPortal/EventCard/EventCard.spec.tsx similarity index 94% rename from src/components/UserPortal/EventCard/EventCard.test.tsx rename to src/components/UserPortal/EventCard/EventCard.spec.tsx index 78aa32abcf..150f676447 100644 --- a/src/components/UserPortal/EventCard/EventCard.test.tsx +++ b/src/components/UserPortal/EventCard/EventCard.spec.tsx @@ -11,7 +11,6 @@ import { Provider } from 'react-redux'; import { store } from 'state/store'; import { StaticMockLink } from 'utils/StaticMockLink'; import userEvent from '@testing-library/user-event'; -import { debug } from 'jest-preview'; import useLocalStorage from 'utils/useLocalstorage'; const { setItem } = useLocalStorage(); @@ -66,7 +65,7 @@ describe('Testing Event Card In User portal', () => { ], }; - test('The card should be rendered properly, and all the details should be displayed correct', async () => { + it('The card should be rendered properly, and all the details should be displayed correct', async () => { const { queryByText } = render( @@ -79,7 +78,6 @@ describe('Testing Event Card In User portal', () => { , ); - debug(); await waitFor(() => expect(queryByText('Test Event')).toBeInTheDocument()); await waitFor(() => expect(queryByText('This is a test event')).toBeInTheDocument(), @@ -105,7 +103,7 @@ describe('Testing Event Card In User portal', () => { await waitFor(() => expect(queryByText('Register')).toBeInTheDocument()); }); - test('When the user is already registered', async () => { + it('When the user is already registered', async () => { setItem('userId', '234'); const { queryByText } = render( @@ -124,7 +122,7 @@ describe('Testing Event Card In User portal', () => { ); }); - test('Handle register should work properly', async () => { + it('Handle register should work properly', async () => { setItem('userId', '456'); const { queryByText } = render( @@ -173,7 +171,7 @@ describe('Event card when start and end time are not given', () => { ], }; - test('Card is rendered correctly', async () => { + it('Card is rendered correctly', async () => { const { container } = render( diff --git a/src/components/UserPortal/OrganizationCard/OrganizationCard.test.tsx b/src/components/UserPortal/OrganizationCard/OrganizationCard.spec.tsx similarity index 69% rename from src/components/UserPortal/OrganizationCard/OrganizationCard.test.tsx rename to src/components/UserPortal/OrganizationCard/OrganizationCard.spec.tsx index ba13fe346d..1aa8c8462a 100644 --- a/src/components/UserPortal/OrganizationCard/OrganizationCard.test.tsx +++ b/src/components/UserPortal/OrganizationCard/OrganizationCard.spec.tsx @@ -1,5 +1,6 @@ -import React, { act } from 'react'; -import { fireEvent, render, screen } from '@testing-library/react'; +import React from 'react'; +import { act, fireEvent, render, screen } from '@testing-library/react'; + import { MockedProvider } from '@apollo/react-testing'; import { I18nextProvider } from 'react-i18next'; @@ -17,15 +18,33 @@ import useLocalStorage from 'utils/useLocalstorage'; import { SEND_MEMBERSHIP_REQUEST, JOIN_PUBLIC_ORGANIZATION, + CANCEL_MEMBERSHIP_REQUEST, } from 'GraphQl/Mutations/OrganizationMutations'; import { toast } from 'react-toastify'; +import { vi } from 'vitest'; +/** + * Unit tests for the OrganizationCard component in the User Portal + * + * These tests validate the behavior and rendering of the OrganizationCard component. + * The tests ensure the component displays properly with various states and that interactions + * such as sending membership requests and visiting organizations work as expected. + * + * 1. **Component should be rendered properly**: Tests if the component renders correctly with the provided props. + * 2. **Component should render properly with an image**: Verifies the component's behavior when an organization image is available. + * 3. **Visit organization**: Simulates a click on the "manage" button and verifies that the user is redirected to the correct organization page. + * 4. **Send membership request**: Tests if the membership request is successfully sent and verifies the success toast message. + * 5. **Send membership request to a public organization**: Validates sending a membership request to a public organization and verifies multiple success toast messages. + * 6. **Withdraw membership request**: Simulates withdrawing a membership request and verifies that the button works as expected. + * + * Mocked GraphQL queries and mutations are used to simulate the backend behavior for testing. + */ const { getItem } = useLocalStorage(); -jest.mock('react-toastify', () => ({ +vi.mock('react-toastify', () => ({ toast: { - success: jest.fn(), - error: jest.fn(), + success: vi.fn(), + error: vi.fn(), }, })); @@ -145,6 +164,21 @@ const MOCKS = [ }, }, }, + { + request: { + query: CANCEL_MEMBERSHIP_REQUEST, + variables: { + membershipRequestId: '56gheqyr7deyfuiwfewifruy8', + }, + }, + result: { + data: { + cancelMembershipRequest: { + _id: '56gheqyr7deyfuiwfewifruy8', + }, + }, + }, + }, ]; const link = new StaticMockLink(MOCKS, true); @@ -188,7 +222,7 @@ let props = { }; describe('Testing OrganizationCard Component [User Portal]', () => { - test('Component should be rendered properly', async () => { + it('Component should be rendered properly', async () => { render( @@ -204,7 +238,7 @@ describe('Testing OrganizationCard Component [User Portal]', () => { await wait(); }); - test('Component should be rendered properly if organization Image is not undefined', async () => { + it('Component should be rendered properly if organization Image is not undefined', async () => { props = { ...props, image: 'organizationImage', @@ -225,7 +259,39 @@ describe('Testing OrganizationCard Component [User Portal]', () => { await wait(); }); - test('Send membership request', async () => { + it('Visit organization', async () => { + const cardProps = { + ...props, + id: '3', + image: 'organizationImage', + userRegistrationRequired: true, + membershipRequestStatus: 'accepted', + }; + + render( + + + + + + + + + , + ); + + await wait(); + + expect(screen.getByTestId('manageBtn')).toBeInTheDocument(); + + fireEvent.click(screen.getByTestId('manageBtn')); + + await wait(); + + expect(window.location.pathname).toBe(`/user/organization/${cardProps.id}`); + }); + + it('Send membership request', async () => { props = { ...props, image: 'organizationImage', @@ -253,7 +319,7 @@ describe('Testing OrganizationCard Component [User Portal]', () => { expect(toast.success).toHaveBeenCalledWith('MembershipRequestSent'); }); - test('send membership request to public org', async () => { + it('send membership request to public org', async () => { const cardProps = { ...props, id: '2', @@ -283,13 +349,21 @@ describe('Testing OrganizationCard Component [User Portal]', () => { expect(toast.success).toHaveBeenCalledTimes(2); }); - test('withdraw membership request', async () => { + it('withdraw membership request', async () => { const cardProps = { ...props, id: '3', image: 'organizationImage', userRegistrationRequired: true, membershipRequestStatus: 'pending', + membershipRequests: [ + { + _id: '56gheqyr7deyfuiwfewifruy8', + user: { + _id: getItem('userId'), + }, + }, + ], }; render( diff --git a/src/components/UserPortal/OrganizationNavbar/OrganizationNavbar.test.tsx b/src/components/UserPortal/OrganizationNavbar/OrganizationNavbar.spec.tsx similarity index 81% rename from src/components/UserPortal/OrganizationNavbar/OrganizationNavbar.test.tsx rename to src/components/UserPortal/OrganizationNavbar/OrganizationNavbar.spec.tsx index 038ff626df..7f9e8e52bb 100644 --- a/src/components/UserPortal/OrganizationNavbar/OrganizationNavbar.test.tsx +++ b/src/components/UserPortal/OrganizationNavbar/OrganizationNavbar.spec.tsx @@ -1,6 +1,5 @@ import React, { act } from 'react'; import { MockedProvider } from '@apollo/react-testing'; -import 'jest-localstorage-mock'; import { render, screen } from '@testing-library/react'; import { I18nextProvider } from 'react-i18next'; import { Provider } from 'react-redux'; @@ -17,6 +16,28 @@ import { PLUGIN_SUBSCRIPTION } from 'GraphQl/Mutations/mutations'; import { createMemoryHistory } from 'history'; import useLocalStorage from 'utils/useLocalstorage'; +import { vi } from 'vitest'; + +/** + * Unit tests for the OrganizationNavbar component. + * + * These tests validate the rendering and behavior of the component, ensuring it renders correctly, + * handles user interactions, and manages language and plugin updates. + * + * 1. **Component rendering**: Verifies correct rendering with provided props and organization details. + * 2. **Navigation on plugin click**: Simulates navigation when a plugin link is clicked. + * 3. **Language switch to English**: Tests if the language changes to English. + * 4. **Language switch to French**: Tests if the language changes to French. + * 5. **Language switch to Hindi**: Tests if the language changes to Hindi. + * 6. **Language switch to Spanish**: Tests if the language changes to Spanish. + * 7. **Language switch to Chinese**: Tests if the language changes to Chinese. + * 8. **Rendering plugins from localStorage**: Verifies correct rendering of plugins from localStorage. + * 9. **Plugin removal on uninstallation**: Ensures plugins are removed when uninstalled for the organization. + * 10. **Rendering plugins when not uninstalled**: Ensures plugins render if not uninstalled. + * 11. **No changes for unmatched plugin**: Ensures no changes when an unrecognized plugin update occurs. + * + * Mocked GraphQL queries and subscriptions simulate backend behavior. + */ const { setItem, removeItem } = useLocalStorage(); @@ -167,23 +188,26 @@ const navbarProps = { currentPage: 'home', }; -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useParams: () => ({ orgId: organizationId }), -})); +vi.mock('react-router-dom', async () => { + const actual = await vi.importActual('react-router-dom'); + return { + ...actual, + useParams: () => ({ orgId: organizationId }), + }; +}); describe('Testing OrganizationNavbar Component [User Portal]', () => { Object.defineProperty(window, 'matchMedia', { writable: true, - value: jest.fn().mockImplementation((query) => ({ + value: vi.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(), + addListener: vi.fn(), // Deprecated + removeListener: vi.fn(), // Deprecated + addEventListener: vi.fn(), + removeEventListener: vi.fn(), + dispatchEvent: vi.fn(), })), }); @@ -193,7 +217,7 @@ describe('Testing OrganizationNavbar Component [User Portal]', () => { }); }); - test('Component should be rendered properly', async () => { + it('Component should be rendered properly', async () => { render( @@ -217,7 +241,7 @@ describe('Testing OrganizationNavbar Component [User Portal]', () => { // expect(screen.getByText('Chat')).toBeInTheDocument(); }); - test('should navigate correctly on clicking a plugin', async () => { + it('should navigate correctly on clicking a plugin', async () => { const history = createMemoryHistory(); render( @@ -240,7 +264,7 @@ describe('Testing OrganizationNavbar Component [User Portal]', () => { expect(history.location.pathname).toBe(`/user/people/${organizationId}`); }); - test('The language is switched to English', async () => { + it('The language is switched to English', async () => { render( @@ -270,7 +294,7 @@ describe('Testing OrganizationNavbar Component [User Portal]', () => { // expect(screen.getByText('Chat')).toBeInTheDocument(); }); - test('The language is switched to fr', async () => { + it('The language is switched to fr', async () => { render( @@ -294,7 +318,7 @@ describe('Testing OrganizationNavbar Component [User Portal]', () => { expect(cookies.get('i18next')).toBe('fr'); }); - test('The language is switched to hi', async () => { + it('The language is switched to hi', async () => { render( @@ -318,7 +342,7 @@ describe('Testing OrganizationNavbar Component [User Portal]', () => { expect(cookies.get('i18next')).toBe('hi'); }); - test('The language is switched to sp', async () => { + it('The language is switched to sp', async () => { render( @@ -342,7 +366,7 @@ describe('Testing OrganizationNavbar Component [User Portal]', () => { expect(cookies.get('i18next')).toBe('sp'); }); - test('The language is switched to zh', async () => { + it('The language is switched to zh', async () => { render( @@ -366,7 +390,7 @@ describe('Testing OrganizationNavbar Component [User Portal]', () => { expect(cookies.get('i18next')).toBe('zh'); }); - test('Component should be rendered properly if plugins are present in localStorage', async () => { + it('Component should be rendered properly if plugins are present in localStorage', async () => { setItem('talawaPlugins', JSON.stringify(testPlugins)); render( @@ -390,7 +414,7 @@ describe('Testing OrganizationNavbar Component [User Portal]', () => { removeItem('talawaPlugins'); }); - test('should remove plugin if uninstalledOrgs contains organizationId', async () => { + it('should remove plugin if uninstalledOrgs contains organizationId', async () => { setItem('talawaPlugins', JSON.stringify(testPlugins)); render( @@ -412,7 +436,7 @@ describe('Testing OrganizationNavbar Component [User Portal]', () => { }); }); - test('should render plugin if uninstalledOrgs does not contain organizationId', async () => { + it('should render plugin if uninstalledOrgs does not contain organizationId', async () => { setItem('talawaPlugins', JSON.stringify(testPlugins)); render( @@ -434,7 +458,7 @@ describe('Testing OrganizationNavbar Component [User Portal]', () => { }); }); - test('should do nothing if pluginName is not found in the rendered plugins', async () => { + it('should do nothing if pluginName is not found in the rendered plugins', async () => { render( diff --git a/src/components/UserPortal/OrganizationSidebar/OrganizationSidebar.test.tsx b/src/components/UserPortal/OrganizationSidebar/OrganizationSidebar.spec.tsx similarity index 73% rename from src/components/UserPortal/OrganizationSidebar/OrganizationSidebar.test.tsx rename to src/components/UserPortal/OrganizationSidebar/OrganizationSidebar.spec.tsx index c08240462a..2559eaae14 100644 --- a/src/components/UserPortal/OrganizationSidebar/OrganizationSidebar.test.tsx +++ b/src/components/UserPortal/OrganizationSidebar/OrganizationSidebar.spec.tsx @@ -13,6 +13,20 @@ import { store } from 'state/store'; import i18nForTest from 'utils/i18nForTest'; import { StaticMockLink } from 'utils/StaticMockLink'; import OrganizationSidebar from './OrganizationSidebar'; +import { vi } from 'vitest'; + +/** + * Unit tests for the OrganizationSidebar component in the User Portal. + * + * These tests validate the rendering and behavior of the OrganizationSidebar component, + * ensuring that it displays correct content based on the availability of members and events. + * + * 1. **Component renders properly when members and events lists are empty**: Verifies the correct display of "No Members to show" and "No Events to show" when both lists are empty. + * 2. **Component renders properly when events list is not empty**: Tests that the events section is rendered correctly when events are available, and "No Events to show" is not displayed. + * 3. **Component renders properly when members list is not empty**: Verifies the correct display of members when available, ensuring "No Members to show" is not displayed. + * + * Mocked GraphQL queries simulate backend responses for members and events lists. + */ const MOCKS = [ { @@ -31,13 +45,14 @@ const MOCKS = [ _id: 1, title: 'Event', description: 'Event Test', - startDate: '', - endDate: '', + startDate: '2024-01-01', + endDate: '2024-01-02', location: 'New Delhi', startTime: '02:00', endTime: '06:00', allDay: false, recurring: false, + attendees: [], recurrenceRule: null, isRecurringEventException: false, isPublic: true, @@ -93,13 +108,17 @@ async function wait(ms = 100): Promise { }); } let mockId = ''; -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useParams: () => ({ orgId: mockId }), -})); + +vi.mock('react-router-dom', async () => { + const actual = await vi.importActual('react-router-dom'); + return { + ...actual, + useParams: () => ({ orgId: mockId }), + }; +}); describe('Testing OrganizationSidebar Component [User Portal]', () => { - test('Component should be rendered properly when members and events list is empty', async () => { + it('Component should be rendered properly when members and events list is empty', async () => { render( @@ -118,7 +137,7 @@ describe('Testing OrganizationSidebar Component [User Portal]', () => { expect(screen.queryByText('No Events to show')).toBeInTheDocument(); }); - test('Component should be rendered properly when events list is not empty', async () => { + it('Component should be rendered properly when events list is not empty', async () => { mockId = 'events'; render( @@ -138,7 +157,7 @@ describe('Testing OrganizationSidebar Component [User Portal]', () => { expect(screen.queryByText('Event')).toBeInTheDocument(); }); - test('Component should be rendered properly when members list is not empty', async () => { + it('Component should be rendered properly when members list is not empty', async () => { mockId = 'members'; render( diff --git a/src/components/UserPortal/PeopleCard/PeopleCard.test.tsx b/src/components/UserPortal/PeopleCard/PeopleCard.spec.tsx similarity index 65% rename from src/components/UserPortal/PeopleCard/PeopleCard.test.tsx rename to src/components/UserPortal/PeopleCard/PeopleCard.spec.tsx index fd5d6c7f93..c725a8d45a 100644 --- a/src/components/UserPortal/PeopleCard/PeopleCard.test.tsx +++ b/src/components/UserPortal/PeopleCard/PeopleCard.spec.tsx @@ -10,6 +10,18 @@ import i18nForTest from 'utils/i18nForTest'; import { StaticMockLink } from 'utils/StaticMockLink'; import PeopleCard from './PeopleCard'; +/** + * Unit tests for the PeopleCard component in the User Portal. + * + * These tests ensure that the PeopleCard component renders correctly with and without an image, + * validating that all information (name, role, email, etc.) is displayed as expected. + * + * 1. **Component renders properly**: Verifies that the component renders correctly with the given props (name, email, role, etc.). + * 2. **Component renders properly if the person image is provided**: Ensures the component correctly displays the image when a valid image URL is passed in the props. + * + * Mocked GraphQL queries are used to simulate backend behavior, though no queries are required for these tests. + */ + const link = new StaticMockLink([], true); async function wait(ms = 100): Promise { @@ -30,7 +42,7 @@ let props = { }; describe('Testing PeopleCard Component [User Portal]', () => { - test('Component should be rendered properly', async () => { + it('Component should be rendered properly', async () => { render( @@ -46,7 +58,7 @@ describe('Testing PeopleCard Component [User Portal]', () => { await wait(); }); - test('Component should be rendered properly if person image is not undefined', async () => { + it('Component should be rendered properly if person image is not undefined', async () => { props = { ...props, image: 'personImage', diff --git a/src/components/UserPortal/PostCard/PostCard.test.tsx b/src/components/UserPortal/PostCard/PostCard.spec.tsx similarity index 89% rename from src/components/UserPortal/PostCard/PostCard.test.tsx rename to src/components/UserPortal/PostCard/PostCard.spec.tsx index f7d9217308..fe3fcf3dc1 100644 --- a/src/components/UserPortal/PostCard/PostCard.test.tsx +++ b/src/components/UserPortal/PostCard/PostCard.spec.tsx @@ -21,14 +21,33 @@ import { UPDATE_POST_MUTATION, } from 'GraphQl/Mutations/mutations'; import useLocalStorage from 'utils/useLocalstorage'; +import { vi } from 'vitest'; + +/** + * Unit tests for the PostCard component in the User Portal. + * + * These tests ensure the PostCard component behaves as expected: + * + * 1. **Component rendering**: Verifies correct rendering with props like title, text, and creator info. + * 2. **Dropdown functionality**: Tests the dropdown for editing and deleting posts. + * 3. **Edit post**: Ensures the post can be edited with a success message. + * 4. **Delete post**: Verifies post deletion works with a success message. + * 5. **Like/unlike post**: Ensures the UI updates when a user likes or unlikes a post. + * 6. **Post image**: Verifies post image rendering. + * 7. **Create comment**: Ensures a comment is created successfully. + * 8. **Like/unlike comment**: Tests liking/unliking comments. + * 9. **Comment modal**: Verifies the comment modal appears when clicked. + * + * Mocked GraphQL data is used for simulating backend behavior. + */ const { setItem, getItem } = useLocalStorage(); -jest.mock('react-toastify', () => ({ +vi.mock('react-toastify', () => ({ toast: { - error: jest.fn(), - info: jest.fn(), - success: jest.fn(), + error: vi.fn(), + info: vi.fn(), + success: vi.fn(), }, })); @@ -164,7 +183,7 @@ async function wait(ms = 100): Promise { const link = new StaticMockLink(MOCKS, true); describe('Testing PostCard Component [User Portal]', () => { - test('Component should be rendered properly', async () => { + it('Component should be rendered properly', async () => { const cardProps = { id: 'postId', userImage: 'image.png', @@ -218,7 +237,7 @@ describe('Testing PostCard Component [User Portal]', () => { id: '2', }, ], - fetchPosts: jest.fn(), + fetchPosts: vi.fn(), }; render( @@ -236,7 +255,7 @@ describe('Testing PostCard Component [User Portal]', () => { await wait(); }); - test('Dropdown component should be rendered properly', async () => { + it('Dropdown component should be rendered properly', async () => { setItem('userId', '2'); const cardProps = { @@ -263,7 +282,7 @@ describe('Testing PostCard Component [User Portal]', () => { id: '2', }, ], - fetchPosts: jest.fn(), + fetchPosts: vi.fn(), }; render( @@ -285,7 +304,7 @@ describe('Testing PostCard Component [User Portal]', () => { expect(screen.getByText('Delete')).toBeInTheDocument(); }); - test('Edit post should work properly', async () => { + it('Edit post should work properly', async () => { setItem('userId', '2'); const cardProps = { @@ -312,7 +331,7 @@ describe('Testing PostCard Component [User Portal]', () => { id: '2', }, ], - fetchPosts: jest.fn(), + fetchPosts: vi.fn(), }; render( @@ -338,10 +357,10 @@ describe('Testing PostCard Component [User Portal]', () => { userEvent.click(screen.getByTestId('editPostBtn')); await wait(); - expect(toast.success).toBeCalledWith('Post updated Successfully'); + expect(toast.success).toHaveBeenCalledWith('Post updated Successfully'); }); - test('Delete post should work properly', async () => { + it('Delete post should work properly', async () => { setItem('userId', '2'); const cardProps = { @@ -368,7 +387,7 @@ describe('Testing PostCard Component [User Portal]', () => { id: '2', }, ], - fetchPosts: jest.fn(), + fetchPosts: vi.fn(), }; render( @@ -388,10 +407,12 @@ describe('Testing PostCard Component [User Portal]', () => { userEvent.click(screen.getByTestId('deletePost')); await wait(); - expect(toast.success).toBeCalledWith('Successfully deleted the Post.'); + expect(toast.success).toHaveBeenCalledWith( + 'Successfully deleted the Post.', + ); }); - test('Component should be rendered properly if user has liked the post', async () => { + it('Component should be rendered properly if user has liked the post', async () => { const beforeUserId = getItem('userId'); setItem('userId', '2'); @@ -419,7 +440,7 @@ describe('Testing PostCard Component [User Portal]', () => { id: '2', }, ], - fetchPosts: jest.fn(), + fetchPosts: vi.fn(), }; render( @@ -441,7 +462,7 @@ describe('Testing PostCard Component [User Portal]', () => { } }); - test('Component should be rendered properly if user unlikes a post', async () => { + it('Component should be rendered properly if user unlikes a post', async () => { const beforeUserId = getItem('userId'); setItem('userId', '2'); @@ -469,7 +490,7 @@ describe('Testing PostCard Component [User Portal]', () => { id: '2', }, ], - fetchPosts: jest.fn(), + fetchPosts: vi.fn(), }; render( @@ -494,7 +515,7 @@ describe('Testing PostCard Component [User Portal]', () => { } }); - test('Component should be rendered properly if user likes a post', async () => { + it('Component should be rendered properly if user likes a post', async () => { const beforeUserId = getItem('userId'); setItem('userId', '2'); @@ -522,7 +543,7 @@ describe('Testing PostCard Component [User Portal]', () => { id: '1', }, ], - fetchPosts: jest.fn(), + fetchPosts: vi.fn(), }; render( @@ -547,7 +568,7 @@ describe('Testing PostCard Component [User Portal]', () => { } }); - test('Component should be rendered properly if post image is defined', async () => { + it('Component should be rendered properly if post image is defined', async () => { const cardProps = { id: '', userImage: 'image.png', @@ -572,7 +593,7 @@ describe('Testing PostCard Component [User Portal]', () => { id: '1', }, ], - fetchPosts: jest.fn(), + fetchPosts: vi.fn(), }; render( @@ -590,7 +611,7 @@ describe('Testing PostCard Component [User Portal]', () => { await wait(); }); - test('Comment is created successfully after create comment button is clicked.', async () => { + it('Comment is created successfully after create comment button is clicked.', async () => { const cardProps = { id: '1', userImage: 'image.png', @@ -615,7 +636,7 @@ describe('Testing PostCard Component [User Portal]', () => { id: '1', }, ], - fetchPosts: jest.fn(), + fetchPosts: vi.fn(), }; render( @@ -699,7 +720,7 @@ describe('Testing PostCard Component [User Portal]', () => { id: '1', }, ], - fetchPosts: jest.fn(), + fetchPosts: vi.fn(), }; const beforeUserId = getItem('userId'); setItem('userId', '2'); @@ -786,7 +807,7 @@ describe('Testing PostCard Component [User Portal]', () => { id: '1', }, ], - fetchPosts: jest.fn(), + fetchPosts: vi.fn(), }; const beforeUserId = getItem('userId'); setItem('userId', '1'); @@ -813,7 +834,7 @@ describe('Testing PostCard Component [User Portal]', () => { setItem('userId', beforeUserId); } }); - test('Comment modal pops when show comments button is clicked.', async () => { + it('Comment modal pops when show comments button is clicked.', async () => { const cardProps = { id: '', userImage: 'image.png', @@ -838,7 +859,7 @@ describe('Testing PostCard Component [User Portal]', () => { id: '1', }, ], - fetchPosts: jest.fn(), + fetchPosts: vi.fn(), }; render( diff --git a/src/components/UserPortal/PromotedPost/PromotedPost.test.tsx b/src/components/UserPortal/PromotedPost/PromotedPost.spec.tsx similarity index 77% rename from src/components/UserPortal/PromotedPost/PromotedPost.test.tsx rename to src/components/UserPortal/PromotedPost/PromotedPost.spec.tsx index 6ec8ec5de7..dc8bb14e2d 100644 --- a/src/components/UserPortal/PromotedPost/PromotedPost.test.tsx +++ b/src/components/UserPortal/PromotedPost/PromotedPost.spec.tsx @@ -10,6 +10,18 @@ import i18nForTest from 'utils/i18nForTest'; import { StaticMockLink } from 'utils/StaticMockLink'; import PromotedPost from './PromotedPost'; +/** + * Unit tests for the PromotedPost component. + * + * 1. **Render check**: Verifies the component renders correctly with props like title and image. + * 2. **Image prop check**: Tests if the component renders correctly with an image. + * 3. **Icon display**: Ensures the icon (StarPurple500Icon) is displayed. + * 4. **Text display**: Checks that the post title is displayed correctly. + * 5. **Image display**: Verifies the correct image is displayed when the image prop is set. + * + * GraphQL data is mocked for backend simulation. + */ + const link = new StaticMockLink([], true); async function wait(ms = 100): Promise { @@ -27,7 +39,7 @@ let props = { }; describe('Testing PromotedPost Test', () => { - test('Component should be rendered properly', async () => { + it('Component should be rendered properly', async () => { render( @@ -43,7 +55,7 @@ describe('Testing PromotedPost Test', () => { await wait(); }); - test('Component should be rendered properly if prop image is not undefined', async () => { + it('Component should be rendered properly if prop image is not undefined', async () => { props = { ...props, image: 'promotedPostImage', @@ -65,7 +77,7 @@ describe('Testing PromotedPost Test', () => { }); }); -test('Component should display the icon correctly', async () => { +it('Component should display the icon correctly', async () => { const { queryByTestId } = render( @@ -84,7 +96,7 @@ test('Component should display the icon correctly', async () => { }); }); -test('Component should display the text correctly', async () => { +it('Component should display the text correctly', async () => { const { queryAllByText } = render( @@ -103,7 +115,7 @@ test('Component should display the text correctly', async () => { }); }); -test('Component should display the image correctly', async () => { +it('Component should display the image correctly', async () => { props = { ...props, image: 'promotedPostImage', diff --git a/src/components/UserPortal/Register/Register.test.tsx b/src/components/UserPortal/Register/Register.spec.tsx similarity index 75% rename from src/components/UserPortal/Register/Register.test.tsx rename to src/components/UserPortal/Register/Register.spec.tsx index f9929a0588..7ca65f8f0d 100644 --- a/src/components/UserPortal/Register/Register.test.tsx +++ b/src/components/UserPortal/Register/Register.spec.tsx @@ -12,6 +12,22 @@ import i18nForTest from 'utils/i18nForTest'; import { StaticMockLink } from 'utils/StaticMockLink'; import Register from './Register'; import { toast } from 'react-toastify'; +import { vi } from 'vitest'; + +/** + * Unit tests for the Register component. + * + * 1. **Render test**: Verifies proper rendering of the Register component. + * 2. **Mode switch to Login**: Ensures that clicking the "setLoginBtn" changes mode to 'login'. + * 3. **Empty email validation**: Checks if toast.error is triggered for empty email. + * 4. **Empty password validation**: Ensures toast.error is called for empty password. + * 5. **Empty first name validation**: Ensures toast.error is called if first name is missing. + * 6. **Empty last name validation**: Verifies toast.error is triggered if last name is missing. + * 7. **Password mismatch validation**: Verifies toast.error is shown if confirm password doesn't match. + * 8. **Successful registration**: Confirms that toast.success is called when valid credentials are entered. + * + * GraphQL mock data is used for testing user registration functionality. + */ const MOCKS = [ { @@ -56,22 +72,22 @@ async function wait(ms = 100): Promise { }); } -jest.mock('react-toastify', () => ({ +vi.mock('react-toastify', () => ({ toast: { - success: jest.fn(), - warn: jest.fn(), - error: jest.fn(), + success: vi.fn(), + warn: vi.fn(), + error: vi.fn(), }, })); -const setCurrentMode: React.Dispatch> = jest.fn(); +const setCurrentMode: React.Dispatch> = vi.fn(); const props = { setCurrentMode, }; describe('Testing Register Component [User Portal]', () => { - test('Component should be rendered properly', async () => { + it('Component should be rendered properly', async () => { render( @@ -87,7 +103,7 @@ describe('Testing Register Component [User Portal]', () => { await wait(); }); - test('Expect the mode to be changed to Login', async () => { + it('Expect the mode to be changed to Login', async () => { render( @@ -104,10 +120,10 @@ describe('Testing Register Component [User Portal]', () => { userEvent.click(screen.getByTestId('setLoginBtn')); - expect(setCurrentMode).toBeCalledWith('login'); + expect(setCurrentMode).toHaveBeenCalledWith('login'); }); - test('Expect toast.error to be called if email input is empty', async () => { + it('Expect toast.error to be called if email input is empty', async () => { render( @@ -124,10 +140,10 @@ describe('Testing Register Component [User Portal]', () => { userEvent.click(screen.getByTestId('registerBtn')); - expect(toast.error).toBeCalledWith('Please enter valid details.'); + expect(toast.error).toHaveBeenCalledWith('Please enter valid details.'); }); - test('Expect toast.error to be called if password input is empty', async () => { + it('Expect toast.error to be called if password input is empty', async () => { render( @@ -145,10 +161,10 @@ describe('Testing Register Component [User Portal]', () => { userEvent.type(screen.getByTestId('emailInput'), formData.email); userEvent.click(screen.getByTestId('registerBtn')); - expect(toast.error).toBeCalledWith('Please enter valid details.'); + expect(toast.error).toHaveBeenCalledWith('Please enter valid details.'); }); - test('Expect toast.error to be called if first name input is empty', async () => { + it('Expect toast.error to be called if first name input is empty', async () => { render( @@ -169,10 +185,10 @@ describe('Testing Register Component [User Portal]', () => { userEvent.click(screen.getByTestId('registerBtn')); - expect(toast.error).toBeCalledWith('Please enter valid details.'); + expect(toast.error).toHaveBeenCalledWith('Please enter valid details.'); }); - test('Expect toast.error to be called if last name input is empty', async () => { + it('Expect toast.error to be called if last name input is empty', async () => { render( @@ -195,7 +211,7 @@ describe('Testing Register Component [User Portal]', () => { userEvent.click(screen.getByTestId('registerBtn')); - expect(toast.error).toBeCalledWith('Please enter valid details.'); + expect(toast.error).toHaveBeenCalledWith('Please enter valid details.'); }); test("Expect toast.error to be called if confirmPassword doesn't match with password", async () => { @@ -223,12 +239,12 @@ describe('Testing Register Component [User Portal]', () => { userEvent.click(screen.getByTestId('registerBtn')); - expect(toast.error).toBeCalledWith( + expect(toast.error).toHaveBeenCalledWith( "Password doesn't match. Confirm Password and try again.", ); }); - test('Expect toast.success to be called if valid credentials are entered.', async () => { + it('Expect toast.success to be called if valid credentials are entered.', async () => { render( @@ -260,7 +276,7 @@ describe('Testing Register Component [User Portal]', () => { await wait(); - expect(toast.success).toBeCalledWith( + expect(toast.success).toHaveBeenCalledWith( 'Successfully registered. Please wait for admin to approve your request.', ); }); diff --git a/src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.test.tsx b/src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.spec.tsx similarity index 77% rename from src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.test.tsx rename to src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.spec.tsx index 93b71b14f1..98459b930a 100644 --- a/src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.test.tsx +++ b/src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.spec.tsx @@ -4,10 +4,20 @@ import { render, screen, waitFor } from '@testing-library/react'; import SecuredRouteForUser from './SecuredRouteForUser'; import useLocalStorage from 'utils/useLocalstorage'; +/** + * Unit tests for SecuredRouteForUser component: + * + * 1. **Logged-in user**: Verifies that the route renders when 'IsLoggedIn' is set to 'TRUE'. + * 2. **Not logged-in user**: Ensures redirection to the login page when 'IsLoggedIn' is 'FALSE'. + * 3. **Logged-in user with admin access**: Checks that the route renders for a logged-in user with 'AdminFor' set (i.e., admin of an organization). + * + * LocalStorage values like 'IsLoggedIn' and 'AdminFor' are set to simulate different user states. + */ + const { setItem } = useLocalStorage(); describe('SecuredRouteForUser', () => { - test('renders the route when the user is logged in', () => { + it('renders the route when the user is logged in', () => { // Set the 'IsLoggedIn' value to 'TRUE' in localStorage to simulate a logged-in user and do not set 'AdminFor' so that it remains undefined. setItem('IsLoggedIn', 'TRUE'); @@ -31,7 +41,7 @@ describe('SecuredRouteForUser', () => { expect(screen.getByTestId('organizations-content')).toBeInTheDocument(); }); - test('redirects to /user when the user is not logged in', async () => { + it('redirects to /user when the user is not logged in', async () => { // Set the user as not logged in in local storage setItem('IsLoggedIn', 'FALSE'); @@ -58,7 +68,7 @@ describe('SecuredRouteForUser', () => { }); }); - test('renders the route when the user is logged in and user is ADMIN', () => { + it('renders the route when the user is logged in and user is ADMIN', () => { // Set the 'IsLoggedIn' value to 'TRUE' in localStorage to simulate a logged-in user and set 'AdminFor' to simulate ADMIN of some Organization. setItem('IsLoggedIn', 'TRUE'); setItem('AdminFor', [ diff --git a/src/components/UserPortal/StartPostModal/StartPostModal.test.tsx b/src/components/UserPortal/StartPostModal/StartPostModal.spec.tsx similarity index 67% rename from src/components/UserPortal/StartPostModal/StartPostModal.test.tsx rename to src/components/UserPortal/StartPostModal/StartPostModal.spec.tsx index 5c436705cd..2d9024bcd3 100644 --- a/src/components/UserPortal/StartPostModal/StartPostModal.test.tsx +++ b/src/components/UserPortal/StartPostModal/StartPostModal.spec.tsx @@ -12,12 +12,26 @@ import { store } from 'state/store'; import { StaticMockLink } from 'utils/StaticMockLink'; import i18nForTest from 'utils/i18nForTest'; import StartPostModal from './StartPostModal'; - -jest.mock('react-toastify', () => ({ +import { vi } from 'vitest'; + +/** + * Unit tests for StartPostModal component: + * + * 1. **Rendering StartPostModal**: Verifies that the modal renders correctly when the `show` prop is set to `true`. + * 2. **Invalid post submission**: Ensures that when the post body is empty, an error toast is shown with the appropriate message ("Can't create a post with an empty body"). + * 3. **Valid post submission**: Checks that a post with valid text triggers an info toast, and simulates the creation of a post with the message "Processing your post. Please wait." + * 4. **User image null**: Confirms that when the user image is null, a default image is displayed instead. + * 5. **User image not null**: Verifies that when the user image is provided, the correct user image is shown. + * + * Mocked GraphQL mutation (`CREATE_POST_MUTATION`) and toast notifications are used to simulate the post creation process. + * The `renderStartPostModal` function is used to render the modal with different user states and input values. + */ + +vi.mock('react-toastify', () => ({ toast: { - error: jest.fn(), - info: jest.fn(), - success: jest.fn(), + error: vi.fn(), + info: vi.fn(), + success: vi.fn(), }, })); @@ -62,8 +76,8 @@ const renderStartPostModal = ( ): RenderResult => { const cardProps = { show: visibility, - onHide: jest.fn(), - fetchPosts: jest.fn(), + onHide: vi.fn(), + fetchPosts: vi.fn(), userData: { user: { __typename: 'User', @@ -113,26 +127,28 @@ const renderStartPostModal = ( describe('Testing StartPostModal Component: User Portal', () => { afterAll(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); }); - test('Check if StartPostModal renders properly', async () => { + it('Check if StartPostModal renders properly', async () => { renderStartPostModal(true, null); const modal = await screen.findByTestId('startPostModal'); expect(modal).toBeInTheDocument(); }); - test('On invalid post submission with empty body Error toast should be shown', async () => { - const toastSpy = jest.spyOn(toast, 'error'); + it('On invalid post submission with empty body Error toast should be shown', async () => { + const toastSpy = vi.spyOn(toast, 'error'); renderStartPostModal(true, null); await wait(); userEvent.click(screen.getByTestId('createPostBtn')); - expect(toastSpy).toBeCalledWith("Can't create a post with an empty body."); + expect(toastSpy).toHaveBeenCalledWith( + "Can't create a post with an empty body.", + ); }); - test('On valid post submission Info toast should be shown', async () => { + it('On valid post submission Info toast should be shown', async () => { renderStartPostModal(true, null); await wait(); @@ -142,15 +158,17 @@ describe('Testing StartPostModal Component: User Portal', () => { userEvent.click(screen.getByTestId('createPostBtn')); - expect(toast.error).not.toBeCalledWith(); - expect(toast.info).toBeCalledWith('Processing your post. Please wait.'); + expect(toast.error).not.toHaveBeenCalledWith(); + expect(toast.info).toHaveBeenCalledWith( + 'Processing your post. Please wait.', + ); // await wait(); // expect(toast.success).toBeCalledWith( // 'Your post is now visible in the feed.', // ); }); - test('If user image is null then default image should be shown', async () => { + it('If user image is null then default image should be shown', async () => { renderStartPostModal(true, null); await wait(); @@ -161,7 +179,7 @@ describe('Testing StartPostModal Component: User Portal', () => { ); }); - test('If user image is not null then user image should be shown', async () => { + it('If user image is not null then user image should be shown', async () => { renderStartPostModal(true, 'image.png'); await wait(); diff --git a/src/components/UserPortal/UserNavbar/UserNavbar.test.tsx b/src/components/UserPortal/UserNavbar/UserNavbar.spec.tsx similarity index 74% rename from src/components/UserPortal/UserNavbar/UserNavbar.test.tsx rename to src/components/UserPortal/UserNavbar/UserNavbar.spec.tsx index 8c3447f25a..6173871dbb 100644 --- a/src/components/UserPortal/UserNavbar/UserNavbar.test.tsx +++ b/src/components/UserPortal/UserNavbar/UserNavbar.spec.tsx @@ -13,6 +13,22 @@ import UserNavbar from './UserNavbar'; import userEvent from '@testing-library/user-event'; import { REVOKE_REFRESH_TOKEN } from 'GraphQl/Mutations/mutations'; +/** + * Unit tests for UserNavbar component [User Portal]: + * + * 1. **Rendering UserNavbar**: Verifies that the `UserNavbar` component renders correctly. + * 2. **Switching language to English**: Ensures that clicking the language dropdown and selecting 'English' updates the language cookie to 'en'. + * 3. **Switching language to French**: Verifies that selecting 'French' updates the language cookie to 'fr'. + * 4. **Switching language to Hindi**: Confirms that choosing 'Hindi' updates the language cookie to 'hi'. + * 5. **Switching language to Spanish**: Ensures that selecting 'Spanish' sets the language cookie to 'sp'. + * 6. **Switching language to Chinese**: Verifies that selecting 'Chinese' changes the language cookie to 'zh'. + * 7. **Interacting with the dropdown menu**: Ensures the user can open the dropdown and see available options like 'Settings' and 'Logout'. + * 8. **Navigating to the 'Settings' page**: Confirms that clicking 'Settings' in the dropdown correctly navigates the user to the "/user/settings" page. + * + * The tests simulate interactions with the language dropdown and the user dropdown menu to ensure proper functionality of language switching and navigation. + * Mocked GraphQL mutation (`REVOKE_REFRESH_TOKEN`) and mock store are used to test the component in an isolated environment. + */ + async function wait(ms = 100): Promise { await act(() => { return new Promise((resolve) => { @@ -39,7 +55,7 @@ describe('Testing UserNavbar Component [User Portal]', () => { }); }); - test('Component should be rendered properly', async () => { + it('Component should be rendered properly', async () => { render( @@ -55,7 +71,7 @@ describe('Testing UserNavbar Component [User Portal]', () => { await wait(); }); - test('The language is switched to English', async () => { + it('The language is switched to English', async () => { render( @@ -79,7 +95,7 @@ describe('Testing UserNavbar Component [User Portal]', () => { expect(cookies.get('i18next')).toBe('en'); }); - test('The language is switched to fr', async () => { + it('The language is switched to fr', async () => { render( @@ -103,7 +119,7 @@ describe('Testing UserNavbar Component [User Portal]', () => { expect(cookies.get('i18next')).toBe('fr'); }); - test('The language is switched to hi', async () => { + it('The language is switched to hi', async () => { render( @@ -127,7 +143,7 @@ describe('Testing UserNavbar Component [User Portal]', () => { expect(cookies.get('i18next')).toBe('hi'); }); - test('The language is switched to sp', async () => { + it('The language is switched to sp', async () => { render( @@ -151,7 +167,7 @@ describe('Testing UserNavbar Component [User Portal]', () => { expect(cookies.get('i18next')).toBe('sp'); }); - test('The language is switched to zh', async () => { + it('The language is switched to zh', async () => { render( @@ -175,7 +191,7 @@ describe('Testing UserNavbar Component [User Portal]', () => { expect(cookies.get('i18next')).toBe('zh'); }); - test('User can see and interact with the dropdown menu', async () => { + it('User can see and interact with the dropdown menu', async () => { render( @@ -195,7 +211,7 @@ describe('Testing UserNavbar Component [User Portal]', () => { expect(screen.getByTestId('logoutBtn')).toBeInTheDocument(); }); - test('User can navigate to the "Settings" page', async () => { + it('User can navigate to the "Settings" page', async () => { render( diff --git a/src/components/UserPortal/UserProfile/EventsAttendedByUser.spec.tsx b/src/components/UserPortal/UserProfile/EventsAttendedByUser.spec.tsx new file mode 100644 index 0000000000..dfdeb5523e --- /dev/null +++ b/src/components/UserPortal/UserProfile/EventsAttendedByUser.spec.tsx @@ -0,0 +1,132 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import { EventsAttendedByUser } from './EventsAttendedByUser'; +import { MockedProvider } from '@apollo/client/testing'; +import { EVENT_DETAILS } from 'GraphQl/Queries/Queries'; + +/** + * Unit tests for EventsAttendedByUser component: + * + * 1. **Rendering with events**: Verifies that the component renders properly when the user has attended events. + * - It checks for the presence of a title ('eventAttended') and ensures the correct number of event cards are rendered (2 events in this case). + * 2. **Rendering without events**: Ensures that when the user has not attended any events, a message indicating no events attended is displayed. + * - It checks for the presence of a 'noeventsAttended' message and ensures no event cards are rendered. + * + * Mock GraphQL queries (using `MockedProvider`) simulate the fetching of event details. + * The tests check the proper handling of different user event attendance scenarios. + */ + +const mockT = (key: string, params?: Record): string => { + if (params) { + return Object.entries(params).reduce( + (acc, [key, value]) => acc.replace(`{{${key}}}`, value), + key, + ); + } + return key; +}; + +const mocks = [ + { + request: { + query: EVENT_DETAILS, + variables: { id: '1' }, + }, + result: { + data: { + event: { + _id: '1', + title: 'Event 1', + startDate: '2023-01-01', + recurring: false, + attendees: [], + organization: { _id: 'org1' }, + }, + }, + }, + }, + { + request: { + query: EVENT_DETAILS, + variables: { id: '2' }, + }, + result: { + data: { + event: { + _id: '2', + title: 'Event 2', + startDate: '2023-01-01', + recurring: false, + attendees: [], + organization: { _id: 'org1' }, + }, + }, + }, + }, +]; + +describe('EventsAttendedByUser Component', () => { + const mockUserWithEvents = { + userDetails: { + firstName: 'John', + lastName: 'Doe', + createdAt: '2023-01-01', + gender: 'Male', + email: 'john@example.com', + phoneNumber: '1234567890', + birthDate: '1990-01-01', + grade: 'A', + empStatus: 'Employed', + maritalStatus: 'Single', + address: '123 Street', + state: 'State', + country: 'Country', + image: 'image.jpg', + eventsAttended: [{ _id: '1' }, { _id: '2' }], + }, + t: mockT, + }; + + const mockUserWithoutEvents = { + userDetails: { + firstName: 'Jane', + lastName: 'Doe', + createdAt: '2023-01-01', + gender: 'Female', + email: 'jane@example.com', + phoneNumber: '0987654321', + birthDate: '1990-01-01', + grade: 'B', + empStatus: 'Unemployed', + maritalStatus: 'Single', + address: '456 Street', + state: 'State', + country: 'Country', + image: 'image.jpg', + eventsAttended: [], + }, + t: mockT, + }; + + it('renders the component with events', () => { + render( + + + , + ); + + expect(screen.getByText('eventAttended')).toBeInTheDocument(); + expect(screen.getAllByTestId('usereventsCard')).toHaveLength(2); + }); + + it('renders no events message when user has no events', () => { + render( + + + , + ); + + expect(screen.getByText('noeventsAttended')).toBeInTheDocument(); + expect(screen.queryByTestId('usereventsCard')).not.toBeInTheDocument(); + }); +}); diff --git a/src/components/UserPortal/UserProfile/EventsAttendedByUser.tsx b/src/components/UserPortal/UserProfile/EventsAttendedByUser.tsx new file mode 100644 index 0000000000..13ab9f5f5a --- /dev/null +++ b/src/components/UserPortal/UserProfile/EventsAttendedByUser.tsx @@ -0,0 +1,57 @@ +import React from 'react'; +import { Card } from 'react-bootstrap'; +import styles from './common.module.css'; +import EventsAttendedByMember from 'components/MemberDetail/EventsAttendedByMember'; +/** + * Component to display events attended by a user in card format + * @param userDetails - User information including attended events + * @param t - Translation function + * @returns Card component containing list of attended events + */ +interface InterfaceUser { + userDetails: { + firstName: string; + lastName: string; + createdAt: string; + gender: string; + email: string; + phoneNumber: string; + birthDate: string; + grade: string; + empStatus: string; + maritalStatus: string; + address: string; + state: string; + country: string; + image: string; + eventsAttended: { _id: string }[]; + }; + t: (key: string) => string; +} +export const EventsAttendedByUser: React.FC = ({ + userDetails, + t, +}) => { + return ( + +
+
{t('eventAttended')}
+
+ + {!userDetails.eventsAttended?.length ? ( +
+
{t('noeventsAttended')}
+
+ ) : ( + userDetails.eventsAttended.map((event: { _id: string }) => ( + + + + )) + )} +
+
+ ); +}; + +export default EventsAttendedByUser; diff --git a/src/components/UserPortal/UserProfile/UserAddressFields.spec.tsx b/src/components/UserPortal/UserProfile/UserAddressFields.spec.tsx new file mode 100644 index 0000000000..9c0a6609e4 --- /dev/null +++ b/src/components/UserPortal/UserProfile/UserAddressFields.spec.tsx @@ -0,0 +1,100 @@ +import React from 'react'; +import { render, screen, fireEvent } from '@testing-library/react'; +import { UserAddressFields } from './UserAddressFields'; +import { countryOptions } from 'utils/formEnumFields'; +import { vi } from 'vitest'; + +/** + * Unit tests for UserAddressFields component: + * + * 1. **Rendering form fields**: Ensures address, state, and country fields are rendered. + * 2. **Displaying translated labels**: Verifies correct translations for labels. + * 3. **Handling input changes**: Tests if `handleFieldChange` is called with correct values for address, state, and country. + * 4. **Rendering country options**: Checks if all country options are displayed. + * 5. **Displaying initial values**: Ensures initial values (address, state, country) are correctly shown. + * + * `fireEvent` simulates user actions, and `vi.fn()` mocks callback functions. + */ + +describe('UserAddressFields', () => { + const mockProps = { + tCommon: (key: string) => `translated_${key}`, + t: (key: string) => `translated_${key}`, + handleFieldChange: vi.fn(), + userDetails: { + address: '123 Test Street', + state: 'Test State', + country: 'US', + }, + }; + + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('renders all form fields correctly', () => { + render(); + + expect(screen.getByTestId('inputAddress')).toBeInTheDocument(); + expect(screen.getByTestId('inputState')).toBeInTheDocument(); + expect(screen.getByTestId('inputCountry')).toBeInTheDocument(); + }); + + it('displays correct labels with translations', () => { + render(); + + expect(screen.getByText('translated_address')).toBeInTheDocument(); + expect(screen.getByText('translated_state')).toBeInTheDocument(); + expect(screen.getByText('translated_country')).toBeInTheDocument(); + }); + + it('handles address input change', () => { + render(); + + const addressInput = screen.getByTestId('inputAddress'); + fireEvent.change(addressInput, { target: { value: 'New Address' } }); + + expect(mockProps.handleFieldChange).toHaveBeenCalledWith( + 'address', + 'New Address', + ); + }); + + it('handles state input change', () => { + render(); + + const stateInput = screen.getByTestId('inputState'); + fireEvent.change(stateInput, { target: { value: 'New State' } }); + + expect(mockProps.handleFieldChange).toHaveBeenCalledWith( + 'state', + 'New State', + ); + }); + + it('handles country selection change', () => { + render(); + + const countrySelect = screen.getByTestId('inputCountry'); + fireEvent.change(countrySelect, { target: { value: 'CA' } }); + + expect(mockProps.handleFieldChange).toHaveBeenCalledWith('country', 'CA'); + }); + + it('renders all country options', () => { + render(); + + const countrySelect = screen.getByTestId('inputCountry'); + const options = countrySelect.getElementsByTagName('option'); + + expect(options.length).toBe(countryOptions.length + 1); // +1 for disabled option + }); + + it('displays initial values correctly', () => { + render(); + + expect(screen.getByTestId('inputAddress')).toHaveValue('123 Test Street'); + expect(screen.getByTestId('inputState')).toHaveValue('Test State'); + expect(screen.getByTestId('inputCountry')).toHaveValue('US'); + }); +}); diff --git a/src/components/UserPortal/UserProfile/UserAddressFields.tsx b/src/components/UserPortal/UserProfile/UserAddressFields.tsx new file mode 100644 index 0000000000..732209f3b0 --- /dev/null +++ b/src/components/UserPortal/UserProfile/UserAddressFields.tsx @@ -0,0 +1,94 @@ +import React from 'react'; +import { countryOptions } from 'utils/formEnumFields'; +import { Col, Form, Row } from 'react-bootstrap'; +import styles from './common.module.css'; + +interface InterfaceUserAddressFieldsProps { + tCommon: (key: string) => string; + t: (key: string) => string; + handleFieldChange: (field: string, value: string) => void; + userDetails: { + address: string; + state: string; + country: string; + }; +} +/** + * Form component containing address-related input fields for user profile + * Includes fields for address, city, state, and country + * @param {Object} props - Component props + * @param {function} props.tCommon - Translation function for common strings + * @param {function} props.t - Translation function for component-specific strings + * @param {function} props.handleFieldChange - Callback for field value changes + * @param {Object} props.userDetails - User's address information + * @returns Form group with address input fields + */ +export const UserAddressFields: React.FC = ({ + tCommon, + t, + handleFieldChange, + userDetails, +}) => { + return ( + + + + {tCommon('address')} + + handleFieldChange('address', e.target.value)} + className={styles.cardControl} + data-testid="inputAddress" + /> + + + + {t('state')} + + handleFieldChange('state', e.target.value)} + className={styles.cardControl} + data-testid="inputState" + /> + + + + {t('country')} + + handleFieldChange('country', e.target.value)} + className={styles.cardControl} + data-testid="inputCountry" + > + + {[...countryOptions] + .sort((a, b) => a.label.localeCompare(b.label)) + .map((country) => ( + + ))} + + + + ); +}; + +export default UserAddressFields; diff --git a/src/components/UserPortal/UserProfile/common.module.css b/src/components/UserPortal/UserProfile/common.module.css new file mode 100644 index 0000000000..a8125dcb3a --- /dev/null +++ b/src/components/UserPortal/UserProfile/common.module.css @@ -0,0 +1,39 @@ +.cardHeader .cardTitle { + font-size: 1.2rem; + font-weight: 600; +} +.scrollableCardBody { + max-height: min(220px, 50vh); + overflow-y: auto; + scroll-behavior: smooth; +} +.cardHeader { + padding: 1.25rem 1rem 1rem 1rem; + border-bottom: 1px solid var(--bs-gray-200); + display: flex; + justify-content: space-between; + align-items: center; +} + +.cardBody { + padding: 1.25rem 1rem 1.5rem 1rem; + display: flex; + flex-direction: column; + overflow-y: scroll; +} + +.cardLabel { + font-weight: bold; + padding-bottom: 1px; + font-size: 14px; + color: #707070; + margin-bottom: 10px; +} + +.cardControl { + margin-bottom: 20px; +} + +.cardButton { + width: fit-content; +} diff --git a/src/components/UserPortal/UserSidebar/UserSidebar.test.tsx b/src/components/UserPortal/UserSidebar/UserSidebar.spec.tsx similarity index 62% rename from src/components/UserPortal/UserSidebar/UserSidebar.test.tsx rename to src/components/UserPortal/UserSidebar/UserSidebar.spec.tsx index 7218bc745c..6435353f89 100644 --- a/src/components/UserPortal/UserSidebar/UserSidebar.test.tsx +++ b/src/components/UserPortal/UserSidebar/UserSidebar.spec.tsx @@ -1,9 +1,9 @@ import React, { act } from 'react'; import type { RenderResult } from '@testing-library/react'; -import { fireEvent, render, screen, waitFor } from '@testing-library/react'; +import { fireEvent, render, screen } from '@testing-library/react'; import { MockedProvider } from '@apollo/react-testing'; import { I18nextProvider } from 'react-i18next'; - +import styles from './UserSidebar.module.css'; import { USER_DETAILS, USER_JOINED_ORGANIZATIONS, @@ -15,6 +15,25 @@ import i18nForTest from 'utils/i18nForTest'; import { StaticMockLink } from 'utils/StaticMockLink'; import UserSidebar from './UserSidebar'; import useLocalStorage from 'utils/useLocalstorage'; +import { vi } from 'vitest'; + +/** + * Unit tests for UserSidebar component: + * + * 1. **Rendering with user data**: Verifies correct rendering when user data is fetched. + * 2. **Logo and title**: Ensures logo, title, and left drawer are visible. + * 3. **Empty organizations list**: Tests rendering when the user has no joined organizations. + * 4. **Organization image rendering**: Verifies rendering when organizations have an image. + * 5. **User profile and links**: Ensures user details and links like 'My Organizations' and 'Settings' are visible. + * 6. **Responsive rendering**: Tests correct rendering and drawer toggle on smaller screens. + * 7. **Active button style**: Verifies button style changes when clicked. + * 8. **Translation display**: Ensures translated text is shown. + * 9. **Sidebar closure on mobile**: Verifies sidebar closes when a link is clicked on mobile view. + * 10. **Drawer visibility on small screens**: Tests drawer visibility toggle based on `hideDrawer` prop. + * 11. **Drawer state change**: Verifies drawer visibility changes when `hideDrawer` prop changes. + * + * `fireEvent` simulates user actions, and `vi.fn()` mocks callback functions. + */ const { setItem } = useLocalStorage(); @@ -27,7 +46,7 @@ const resizeWindow = (width: number): void => { const props = { hideDrawer: true, - setHideDrawer: jest.fn(), + setHideDrawer: vi.fn(), }; const MOCKS = [ @@ -363,40 +382,57 @@ const renderUserSidebar = ( ); }; -describe('Testing UserSidebar Component [User Portal]', () => { +describe('UserSidebar Component Tests in User Portal', () => { beforeEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); }); - test('Component should be rendered properly', async () => { + it('UserSidebar component renders correctly with user data present', async () => { await act(async () => { renderUserSidebar('properId', link); await wait(); }); + expect(screen.getByText('Talawa User Portal')).toBeInTheDocument(); }); - test('Component should be rendered properly when userImage is present', async () => { + it('Displays the logo and title text of the User Portal', async () => { await act(async () => { - renderUserSidebar('imagePresent', link); + renderUserSidebar('properId', link); await wait(); }); + expect(screen.getByText('Talawa User Portal')).toBeInTheDocument(); + expect(screen.getByTestId('leftDrawerContainer')).toBeVisible(); }); - test('Component should be rendered properly when organizationImage is present', async () => { + it('UserSidebar renders correctly when joinedOrganizations list is empty', async () => { + await act(async () => { + renderUserSidebar('orgEmpty', link); + await wait(); + }); + expect(screen.getByText('My Organizations')).toBeInTheDocument(); + }); + + it('Renders UserSidebar component with organization image when present', async () => { await act(async () => { renderUserSidebar('imagePresent', link); await wait(); }); + expect(screen.getByText('Settings')).toBeInTheDocument(); }); - test('Component should be rendered properly when joinedOrganizations list is empty', async () => { + it('User profile data renders with all expected navigation links visible', async () => { await act(async () => { - renderUserSidebar('orgEmpty', link); + renderUserSidebar('properId', link); await wait(); }); + + const expectedLinks = ['My Organizations', 'Settings']; + expectedLinks.forEach((link) => { + expect(screen.getByText(link)).toBeInTheDocument(); + }); }); - test('Testing Drawer when the screen size is less than or equal to 820px', async () => { + it('UserSidebar renders correctly on smaller screens and toggles drawer visibility', async () => { await act(async () => { resizeWindow(800); render( @@ -411,28 +447,124 @@ describe('Testing UserSidebar Component [User Portal]', () => {
, ); }); - expect(screen.getByText('My Organizations')).toBeInTheDocument(); - expect(screen.getByText('Settings')).toBeInTheDocument(); - expect(screen.getByText('Talawa User Portal')).toBeInTheDocument(); - const settingsBtn = screen.getByText('Settings'); + const orgsBtn = screen.getByTestId('orgsBtn'); + act(() => orgsBtn.click()); + expect(props.setHideDrawer).toHaveBeenCalledWith(true); + }); + + it('Active route button style changes correctly upon click', async () => { + await act(async () => { + renderUserSidebar('properId', link); + await wait(); + }); + + const orgsBtn = screen.getByTestId('orgsBtn'); + const settingsBtn = screen.getByTestId('settingsBtn'); + + fireEvent.click(orgsBtn); + expect(orgsBtn).toHaveClass('text-white btn btn-success'); + fireEvent.click(settingsBtn); + expect(settingsBtn).toHaveClass('text-white btn btn-success'); + }); - const orgsBtn = screen.getAllByTestId(/orgsBtn/i); + it('Translation hook displays expected text in UserSidebar', async () => { + await act(async () => { + renderUserSidebar('properId', link); + await wait(); + }); + expect( + screen.getByText(i18nForTest.t('common:settings')), + ).toBeInTheDocument(); + }); + + it('handleLinkClick function closes the sidebar on mobile view when a link is clicked', async () => { + resizeWindow(800); + await act(async () => { + renderUserSidebar('properId', link); + await wait(); + }); + const settingsBtn = screen.getByTestId('settingsBtn'); + fireEvent.click(settingsBtn); + expect(props.setHideDrawer).toHaveBeenCalledWith(true); + }); + + describe('UserSidebar Drawer Visibility Tests on Smaller Screens', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('Clicking a link closes the drawer when window width is 820px or less', () => { + act(() => { + window.innerWidth = 820; + window.dispatchEvent(new Event('resize')); + }); + + render( + + + + + + + + + , + ); - act(() => { - orgsBtn[0].click(); + const linkElement = screen.getByText('My Organizations'); // Adjust text if different + fireEvent.click(linkElement); + + expect(props.setHideDrawer).toHaveBeenCalledWith(true); }); - await waitFor(() => - expect( - orgsBtn[0].className.includes('text-white btn btn-success'), - ).toBeTruthy(), - ); - act(() => { - settingsBtn.click(); + + describe('UserSidebar Drawer State Tests', () => { + it('Drawer visibility changes based on hideDrawer prop', () => { + const { rerender } = render( + + + + + + + + + , + ); + + expect(screen.getByTestId('leftDrawerContainer')).toHaveClass( + styles.hideElemByDefault, + ); + + rerender( + + + + + + + + + , + ); + expect(screen.getByTestId('leftDrawerContainer')).toHaveClass( + styles.inactiveDrawer, + ); + + rerender( + + + + + + + + + , + ); + expect(screen.getByTestId('leftDrawerContainer')).toHaveClass( + styles.activeDrawer, + ); + }); }); - 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 5e258f8a8e..010d8d0e52 100644 --- a/src/components/UserPortal/UserSidebar/UserSidebar.tsx +++ b/src/components/UserPortal/UserSidebar/UserSidebar.tsx @@ -4,7 +4,6 @@ import { useTranslation } from 'react-i18next'; import { NavLink } from 'react-router-dom'; 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'; @@ -109,28 +108,6 @@ const userSidebar = ({ )} - - {({ isActive }) => ( - - )} -
diff --git a/src/components/UserPortal/UserSidebarOrg/UserSidebarOrg.test.tsx b/src/components/UserPortal/UserSidebarOrg/UserSidebarOrg.spec.tsx similarity index 86% rename from src/components/UserPortal/UserSidebarOrg/UserSidebarOrg.test.tsx rename to src/components/UserPortal/UserSidebarOrg/UserSidebarOrg.spec.tsx index 2f28d9afd1..f26997f572 100644 --- a/src/components/UserPortal/UserSidebarOrg/UserSidebarOrg.test.tsx +++ b/src/components/UserPortal/UserSidebarOrg/UserSidebarOrg.spec.tsx @@ -1,10 +1,8 @@ import React, { act } from 'react'; import { fireEvent, render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import 'jest-localstorage-mock'; import { I18nextProvider } from 'react-i18next'; import { BrowserRouter } from 'react-router-dom'; - import i18nForTest from 'utils/i18nForTest'; import type { InterfaceUserSidebarOrgProps } from './UserSidebarOrg'; import UserSidebarOrg from './UserSidebarOrg'; @@ -15,7 +13,24 @@ import { ORGANIZATIONS_LIST } from 'GraphQl/Queries/Queries'; import { StaticMockLink } from 'utils/StaticMockLink'; import { REVOKE_REFRESH_TOKEN } from 'GraphQl/Mutations/mutations'; import useLocalStorage from 'utils/useLocalstorage'; +import { vi } from 'vitest'; +/** + * Unit tests for UserSidebarOrg component: + * + * 1. **Rendering with organization data**: Verifies correct rendering when data is fetched. + * 2. **Profile Page & Modal**: Ensures profile button and organization details modal appear. + * 3. **Menu Navigation**: Tests correct navigation when menu buttons like 'People' are clicked. + * 4. **Responsive Design**: Verifies sidebar behavior on screens. + * 5. **Organization Image**: Ensures correct rendering of organization image. + * 6. **Empty Organizations**: Verifies error message when no organizations exist. + * 7. **Drawer Visibility**: Tests drawer visibility with `hideDrawer` prop values. + * 8. **User Profile Rendering**: Confirms user details are displayed. + * 9. **Translation Display**: Ensures proper translation of UI text. + * 10. **Toast Notifications Mocking**: Mocks toast notifications during tests. + * + * `fireEvent` simulates user actions, and `vi.fn()` mocks callback functions. + */ const { setItem } = useLocalStorage(); const props: InterfaceUserSidebarOrgProps = { @@ -47,7 +62,7 @@ const props: InterfaceUserSidebarOrgProps = { }, ], hideDrawer: false, - setHideDrawer: jest.fn(), + setHideDrawer: vi.fn(), }; const MOCKS = [ @@ -213,11 +228,11 @@ const defaultScreens = [ 'All Organizations', ]; -jest.mock('react-toastify', () => ({ +vi.mock('react-toastify', () => ({ toast: { - success: jest.fn(), - warn: jest.fn(), - error: jest.fn(), + success: vi.fn(), + warn: vi.fn(), + error: vi.fn(), }, })); @@ -244,7 +259,7 @@ beforeEach(() => { }); afterEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); localStorage.clear(); }); @@ -253,7 +268,7 @@ const linkImage = new StaticMockLink(MOCKS_WITH_IMAGE, true); const linkEmpty = new StaticMockLink(MOCKS_EMPTY, true); describe('Testing LeftDrawerOrg component for SUPERADMIN', () => { - test('Component should be rendered properly', async () => { + it('Component should be rendered properly', async () => { setItem('UserImage', ''); setItem('SuperAdmin', true); setItem('FirstName', 'John'); @@ -275,7 +290,7 @@ describe('Testing LeftDrawerOrg component for SUPERADMIN', () => { }); }); - test('Testing Profile Page & Organization Detail Modal', async () => { + it('Testing Profile Page & Organization Detail Modal', async () => { setItem('UserImage', ''); setItem('SuperAdmin', true); setItem('FirstName', 'John'); @@ -295,7 +310,7 @@ describe('Testing LeftDrawerOrg component for SUPERADMIN', () => { expect(screen.getByTestId(/orgBtn/i)).toBeInTheDocument(); }); - test('Testing Menu Buttons', async () => { + it('Testing Menu Buttons', async () => { setItem('UserImage', ''); setItem('SuperAdmin', true); setItem('FirstName', 'John'); @@ -316,7 +331,7 @@ describe('Testing LeftDrawerOrg component for SUPERADMIN', () => { expect(global.window.location.pathname).toContain('/user/people/123'); }); - test('Testing when screen size is less than 820px', async () => { + it('Testing when screen size is less than 820px', async () => { setItem('SuperAdmin', true); render( @@ -339,7 +354,7 @@ describe('Testing LeftDrawerOrg component for SUPERADMIN', () => { expect(window.location.pathname).toContain('user/people/123'); }); - test('Testing when image is present for Organization', async () => { + it('Testing when image is present for Organization', async () => { setItem('UserImage', ''); setItem('SuperAdmin', true); setItem('FirstName', 'John'); @@ -358,7 +373,7 @@ describe('Testing LeftDrawerOrg component for SUPERADMIN', () => { await wait(); }); - test('Testing when Organization does not exists', async () => { + it('Testing when Organization does not exists', async () => { setItem('UserImage', ''); setItem('SuperAdmin', true); setItem('FirstName', 'John'); @@ -380,7 +395,7 @@ describe('Testing LeftDrawerOrg component for SUPERADMIN', () => { ).toBeInTheDocument(); }); - test('Testing Drawer when hideDrawer is null', () => { + it('Testing Drawer when hideDrawer is null', () => { setItem('UserImage', ''); setItem('SuperAdmin', true); setItem('FirstName', 'John'); @@ -398,7 +413,7 @@ describe('Testing LeftDrawerOrg component for SUPERADMIN', () => { ); }); - test('Testing Drawer when hideDrawer is true', () => { + it('Testing Drawer when hideDrawer is true', () => { setItem('UserImage', ''); setItem('SuperAdmin', true); setItem('FirstName', 'John'); diff --git a/src/components/UserProfileSettings/DeleteUser.test.tsx b/src/components/UserProfileSettings/DeleteUser.spec.tsx similarity index 90% rename from src/components/UserProfileSettings/DeleteUser.test.tsx rename to src/components/UserProfileSettings/DeleteUser.spec.tsx index 34ab44fbe5..d089d82607 100644 --- a/src/components/UserProfileSettings/DeleteUser.test.tsx +++ b/src/components/UserProfileSettings/DeleteUser.spec.tsx @@ -5,9 +5,10 @@ import { BrowserRouter } from 'react-router-dom'; import { I18nextProvider } from 'react-i18next'; import i18nForTest from 'utils/i18nForTest'; import DeleteUser from './DeleteUser'; +import { describe, it, expect } from 'vitest'; describe('Delete User component', () => { - test('renders delete user correctly', () => { + it('renders delete user correctly', () => { const { getByText, getAllByText } = render( diff --git a/src/components/UserProfileSettings/OtherSettings.test.tsx b/src/components/UserProfileSettings/OtherSettings.spec.tsx similarity index 89% rename from src/components/UserProfileSettings/OtherSettings.test.tsx rename to src/components/UserProfileSettings/OtherSettings.spec.tsx index 990a430931..490ad2322c 100644 --- a/src/components/UserProfileSettings/OtherSettings.test.tsx +++ b/src/components/UserProfileSettings/OtherSettings.spec.tsx @@ -5,9 +5,10 @@ import { BrowserRouter } from 'react-router-dom'; import { I18nextProvider } from 'react-i18next'; import i18nForTest from 'utils/i18nForTest'; import OtherSettings from './OtherSettings'; +import { describe, it, expect } from 'vitest'; describe('Delete User component', () => { - test('renders delete user correctly', () => { + it('renders delete user correctly', () => { const { getByText } = render( diff --git a/src/components/UserProfileSettings/UserProfile.test.tsx b/src/components/UserProfileSettings/UserProfile.spec.tsx similarity index 92% rename from src/components/UserProfileSettings/UserProfile.test.tsx rename to src/components/UserProfileSettings/UserProfile.spec.tsx index 82caad5d81..dbf7987789 100644 --- a/src/components/UserProfileSettings/UserProfile.test.tsx +++ b/src/components/UserProfileSettings/UserProfile.spec.tsx @@ -5,9 +5,10 @@ import { MockedProvider } from '@apollo/react-testing'; import { BrowserRouter } from 'react-router-dom'; import { I18nextProvider } from 'react-i18next'; import i18nForTest from 'utils/i18nForTest'; +import { describe, it, expect } from 'vitest'; describe('UserProfile component', () => { - test('renders user profile details correctly', () => { + it('renders user profile details correctly', () => { const userDetails = { firstName: 'Christopher', lastName: 'Doe', diff --git a/src/components/UsersTableItem/UserTableItem.test.tsx b/src/components/UsersTableItem/UserTableItem.spec.tsx similarity index 97% rename from src/components/UsersTableItem/UserTableItem.test.tsx rename to src/components/UsersTableItem/UserTableItem.spec.tsx index e87b41f7f2..a0b0c39c86 100644 --- a/src/components/UsersTableItem/UserTableItem.test.tsx +++ b/src/components/UsersTableItem/UserTableItem.spec.tsx @@ -13,11 +13,9 @@ const link = new StaticMockLink(MOCKS, true); const link2 = new StaticMockLink(MOCKS2, true); const link3 = new StaticMockLink(MOCKS_UPDATE, true); import useLocalStorage from 'utils/useLocalstorage'; -import { - REMOVE_ADMIN_MUTATION, - REMOVE_MEMBER_MUTATION, -} from 'GraphQl/Mutations/mutations'; import userEvent from '@testing-library/user-event'; +import { vi } from 'vitest'; +import type * as RouterTypes from 'react-router-dom'; const { setItem } = useLocalStorage(); @@ -28,29 +26,34 @@ async function wait(ms = 100): Promise { }); }); } -const resetAndRefetchMock = jest.fn(); +const resetAndRefetchMock = vi.fn(); -jest.mock('react-toastify', () => ({ +vi.mock('react-toastify', () => ({ toast: { - success: jest.fn(), - error: jest.fn(), - warning: jest.fn(), + success: vi.fn(), + error: vi.fn(), + warning: vi.fn(), }, })); Object.defineProperty(window, 'location', { value: { - replace: jest.fn(), + replace: vi.fn(), }, writable: true, }); -const mockNavgatePush = jest.fn(); +const mockNavgatePush = vi.fn(); -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useNavigate: () => mockNavgatePush, -})); +vi.mock('react-router-dom', async () => { + const actual = (await vi.importActual( + 'react-router-dom', + )) as typeof RouterTypes; + return { + ...actual, + useNavigate: () => mockNavgatePush, + }; +}); beforeEach(() => { setItem('SuperAdmin', true); @@ -59,11 +62,11 @@ beforeEach(() => { afterEach(() => { localStorage.clear(); - jest.clearAllMocks(); + vi.clearAllMocks(); }); describe('Testing User Table Item', () => { - console.error = jest.fn((message) => { + console.error = vi.fn((message) => { if (message.includes('validateDOMNesting')) { return; } @@ -499,12 +502,12 @@ describe('Testing User Table Item', () => { fireEvent.click(searchBtn); // Click on Creator Link fireEvent.click(screen.getByTestId(`creatorabc`)); - expect(toast.success).toBeCalledWith('Profile Page Coming Soon !'); + expect(toast.success).toHaveBeenCalledWith('Profile Page Coming Soon !'); // Click on Organization Link fireEvent.click(screen.getByText(/Joined Organization 1/i)); - expect(window.location.replace).toBeCalledWith('/orgdash/abc'); - expect(mockNavgatePush).toBeCalledWith('/orgdash/abc'); + expect(window.location.replace).toHaveBeenCalledWith('/orgdash/abc'); + expect(mockNavgatePush).toHaveBeenCalledWith('/orgdash/abc'); fireEvent.click(screen.getByTestId(`closeJoinedOrgsBtn${123}`)); }); @@ -693,7 +696,7 @@ describe('Testing User Table Item', () => { expect(screen.getByTestId('removeUserFromOrgBtnmno')).toBeInTheDocument(); // Click on Creator Link fireEvent.click(screen.getByTestId(`creatorxyz`)); - expect(toast.success).toBeCalledWith('Profile Page Coming Soon !'); + expect(toast.success).toHaveBeenCalledWith('Profile Page Coming Soon !'); // Search for Blocked Organization 1 const searchBtn = screen.getByTestId(`searchBtnOrgsBlockedBy`); @@ -720,8 +723,8 @@ describe('Testing User Table Item', () => { // Click on Organization Link fireEvent.click(screen.getByText(/XYZ/i)); - expect(window.location.replace).toBeCalledWith('/orgdash/xyz'); - expect(mockNavgatePush).toBeCalledWith('/orgdash/xyz'); + expect(window.location.replace).toHaveBeenCalledWith('/orgdash/xyz'); + expect(mockNavgatePush).toHaveBeenCalledWith('/orgdash/xyz'); fireEvent.click(screen.getByTestId(`closeBlockedByOrgsBtn${123}`)); }); @@ -1183,25 +1186,6 @@ describe('Testing User Table Item', () => { resetAndRefetch: resetAndRefetchMock, }; - const mocks = [ - { - request: { - query: REMOVE_MEMBER_MUTATION, - variables: { - userId: '123', - orgId: 'xyz', - }, - }, - result: { - errors: [ - { - message: 'User does not exist', - }, - ], - }, - }, - ]; - render( diff --git a/src/components/Venues/VenueCard.tsx b/src/components/Venues/VenueCard.tsx index 752ac95139..43da734bd6 100644 --- a/src/components/Venues/VenueCard.tsx +++ b/src/components/Venues/VenueCard.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { Card, Button } from 'react-bootstrap'; import defaultImg from 'assets/images/defaultImg.png'; import PeopleIcon from 'assets/svgs/people.svg?react'; -import styles from 'screens/OrganizationVenues/OrganizationVenues.module.css'; +import styles from '../../style/app.module.css'; import { useTranslation } from 'react-i18next'; import type { InterfaceQueryVenueListItem } from 'utils/interfaces'; diff --git a/src/components/Venues/VenueModal.test.tsx b/src/components/Venues/VenueModal.spec.tsx similarity index 93% rename from src/components/Venues/VenueModal.test.tsx rename to src/components/Venues/VenueModal.spec.tsx index b299c8ff20..45560c40cb 100644 --- a/src/components/Venues/VenueModal.test.tsx +++ b/src/components/Venues/VenueModal.spec.tsx @@ -4,7 +4,6 @@ import type { RenderResult } from '@testing-library/react'; import { render, screen, fireEvent } from '@testing-library/react'; import { Provider } from 'react-redux'; import { BrowserRouter } from 'react-router-dom'; -import 'jest-location-mock'; import { I18nextProvider } from 'react-i18next'; import type { InterfaceVenueModalProps } from './VenueModal'; @@ -19,6 +18,8 @@ import { UPDATE_VENUE_MUTATION, } from 'GraphQl/Mutations/mutations'; import type { ApolloLink } from '@apollo/client'; +import { vi } from 'vitest'; +import type * as RouterTypes from 'react-router-dom'; const MOCKS = [ { @@ -65,10 +66,16 @@ const MOCKS = [ const link = new StaticMockLink(MOCKS, true); const mockId = 'orgId'; -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useParams: () => ({ orgId: mockId }), -})); + +vi.mock('react-router-dom', async () => { + const actual = (await vi.importActual( + 'react-router-dom', + )) as typeof RouterTypes; + return { + ...actual, + useParams: () => ({ orgId: mockId }), + }; +}); async function wait(ms = 100): Promise { await act(() => { @@ -78,26 +85,26 @@ async function wait(ms = 100): Promise { }); } -jest.mock('react-toastify', () => ({ +vi.mock('react-toastify', () => ({ toast: { - success: jest.fn(), - warning: jest.fn(), - error: jest.fn(), + success: vi.fn(), + warning: vi.fn(), + error: vi.fn(), }, })); const props: InterfaceVenueModalProps[] = [ { show: true, - onHide: jest.fn(), + onHide: vi.fn(), edit: false, venueData: null, - refetchVenues: jest.fn(), + refetchVenues: vi.fn(), orgId: 'orgId', }, { show: true, - onHide: jest.fn(), + onHide: vi.fn(), edit: true, venueData: { _id: 'venue1', @@ -106,7 +113,7 @@ const props: InterfaceVenueModalProps[] = [ image: 'image1', capacity: '100', }, - refetchVenues: jest.fn(), + refetchVenues: vi.fn(), orgId: 'orgId', }, ]; @@ -129,7 +136,7 @@ const renderVenueModal = ( }; describe('VenueModal', () => { - global.alert = jest.fn(); + global.alert = vi.fn(); test('renders correctly when show is true', async () => { renderVenueModal(props[0], link); diff --git a/src/components/Venues/VenueModal.tsx b/src/components/Venues/VenueModal.tsx index 476964b910..1d0fbe0af4 100644 --- a/src/components/Venues/VenueModal.tsx +++ b/src/components/Venues/VenueModal.tsx @@ -1,6 +1,6 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'; import { Button, Form, Modal } from 'react-bootstrap'; -import styles from './VenueModal.module.css'; +import styles from '../../style/app.module.css'; import { toast } from 'react-toastify'; import { useTranslation } from 'react-i18next'; import { useMutation } from '@apollo/client'; @@ -162,8 +162,7 @@ const VenueModal = ({
-
+
{/* Dropdown for filtering members */} {/* Dropdown for sorting by name */}
} + /> + + + + + + , + ); +}; + +/** Mock useParams to provide consistent test data */ + +describe('Testing VolunteerGroups Screen', () => { + beforeAll(() => { + vi.mock('react-router-dom', async () => { + const actualDom = await vi.importActual('react-router-dom'); + return { + ...actualDom, + useParams: vi.fn(), + }; + }); + }); + + afterAll(() => { + vi.clearAllMocks(); + }); + + const mockRouteParams = (orgId = 'orgId', eventId = 'eventId'): void => { + vi.mocked(useParams).mockReturnValue({ orgId, eventId }); + }; + + it('should redirect to fallback URL if URL params are undefined', async () => { + /** Mocking the useParams hook to return undefined parameters */ + mockRouteParams('', ''); + render( + + + + + + } /> +
} + /> + + + + + , + ); + + await waitFor(() => { + expect(screen.getByTestId('paramsError')).toBeInTheDocument(); + }); + }); + + it('should render Groups screen', async () => { + mockRouteParams(); + renderVolunteerGroups(link1); + const searchInput = await screen.findByTestId('searchBy'); + expect(searchInput).toBeInTheDocument(); + }); + + it('Check Sorting Functionality', async () => { + mockRouteParams(); + renderVolunteerGroups(link1); + const searchInput = await screen.findByTestId('searchBy'); + expect(searchInput).toBeInTheDocument(); + + let sortBtn = await screen.findByTestId('sort'); + expect(sortBtn).toBeInTheDocument(); + + // Sort by members_DESC + fireEvent.click(sortBtn); + const volunteersDESC = await screen.findByTestId('volunteers_DESC'); + expect(volunteersDESC).toBeInTheDocument(); + fireEvent.click(volunteersDESC); + + let groupName = await screen.findAllByTestId('groupName'); + expect(groupName[0]).toHaveTextContent('Group 1'); + + // Sort by members_ASC + sortBtn = await screen.findByTestId('sort'); + expect(sortBtn).toBeInTheDocument(); + fireEvent.click(sortBtn); + const volunteersASC = await screen.findByTestId('volunteers_ASC'); + expect(volunteersASC).toBeInTheDocument(); + fireEvent.click(volunteersASC); + + groupName = await screen.findAllByTestId('groupName'); + expect(groupName[0]).toHaveTextContent('Group 2'); + }); + + it('Search by Groups', async () => { + mockRouteParams(); + renderVolunteerGroups(link1); + const searchInput = await screen.findByTestId('searchBy'); + expect(searchInput).toBeInTheDocument(); + + const searchToggle = await screen.findByTestId('searchByToggle'); + expect(searchToggle).toBeInTheDocument(); + userEvent.click(searchToggle); + + const searchByGroup = await screen.findByTestId('group'); + expect(searchByGroup).toBeInTheDocument(); + userEvent.click(searchByGroup); + + userEvent.type(searchInput, '1'); + await debounceWait(); + + const groupName = await screen.findAllByTestId('groupName'); + expect(groupName[0]).toHaveTextContent('Group 1'); + }); + + it('Search by Leader', async () => { + mockRouteParams(); + renderVolunteerGroups(link1); + const searchInput = await screen.findByTestId('searchBy'); + expect(searchInput).toBeInTheDocument(); + + const searchToggle = await screen.findByTestId('searchByToggle'); + expect(searchToggle).toBeInTheDocument(); + userEvent.click(searchToggle); + + const searchByLeader = await screen.findByTestId('leader'); + expect(searchByLeader).toBeInTheDocument(); + userEvent.click(searchByLeader); + + // Search by name on press of ENTER + userEvent.type(searchInput, 'Bruce'); + await debounceWait(); + + const groupName = await screen.findAllByTestId('groupName'); + expect(groupName[0]).toHaveTextContent('Group 1'); + }); + + it('should render screen with No Groups', async () => { + mockRouteParams(); + renderVolunteerGroups(link3); + + await waitFor(() => { + expect(screen.getByTestId('searchBy')).toBeInTheDocument(); + expect(screen.getByText(t.noVolunteerGroups)).toBeInTheDocument(); + }); + }); + + it('Error while fetching groups data', async () => { + mockRouteParams(); + renderVolunteerGroups(link2); + + await waitFor(() => { + expect(screen.getByTestId('errorMsg')).toBeInTheDocument(); + }); + }); + + it('Open and close ViewModal', async () => { + mockRouteParams(); + renderVolunteerGroups(link1); + + const viewGroupBtn = await screen.findAllByTestId('viewGroupBtn'); + userEvent.click(viewGroupBtn[0]); + + expect(await screen.findByText(t.groupDetails)).toBeInTheDocument(); + userEvent.click(await screen.findByTestId('volunteerViewModalCloseBtn')); + }); + + it('Open and Close Delete Modal', async () => { + mockRouteParams(); + renderVolunteerGroups(link1); + + const deleteGroupBtn = await screen.findAllByTestId('deleteGroupBtn'); + userEvent.click(deleteGroupBtn[0]); + + expect(await screen.findByText(t.deleteGroup)).toBeInTheDocument(); + userEvent.click(await screen.findByTestId('modalCloseBtn')); + }); + + it('Open and close GroupModal (Edit)', async () => { + mockRouteParams(); + renderVolunteerGroups(link1); + + const editGroupBtn = await screen.findAllByTestId('editGroupBtn'); + userEvent.click(editGroupBtn[0]); + + expect(await screen.findAllByText(t.updateGroup)).toHaveLength(2); + userEvent.click(await screen.findByTestId('modalCloseBtn')); + }); + + it('Open and close GroupModal (Create)', async () => { + mockRouteParams(); + renderVolunteerGroups(link1); + + const createGroupBtn = await screen.findByTestId('createGroupBtn'); + userEvent.click(createGroupBtn); + + expect(await screen.findAllByText(t.createGroup)).toHaveLength(2); + userEvent.click(await screen.findByTestId('modalCloseBtn')); + }); +}); diff --git a/src/screens/EventVolunteers/VolunteerGroups/VolunteerGroups.tsx b/src/screens/EventVolunteers/VolunteerGroups/VolunteerGroups.tsx new file mode 100644 index 0000000000..3c70b1db49 --- /dev/null +++ b/src/screens/EventVolunteers/VolunteerGroups/VolunteerGroups.tsx @@ -0,0 +1,444 @@ +import React, { useCallback, useMemo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Button, Dropdown, Form } from 'react-bootstrap'; +import { Navigate, useParams } from 'react-router-dom'; + +import { Search, Sort, WarningAmberRounded } from '@mui/icons-material'; + +import { useQuery } from '@apollo/client'; + +import type { InterfaceVolunteerGroupInfo } from 'utils/interfaces'; +import Loader from 'components/Loader/Loader'; +import { + DataGrid, + type GridCellParams, + type GridColDef, +} from '@mui/x-data-grid'; +import { debounce, Stack } from '@mui/material'; +import Avatar from 'components/Avatar/Avatar'; +import styles from '../../../style/app.module.css'; +import { EVENT_VOLUNTEER_GROUP_LIST } from 'GraphQl/Queries/EventVolunteerQueries'; +import VolunteerGroupModal from './VolunteerGroupModal'; +import VolunteerGroupDeleteModal from './VolunteerGroupDeleteModal'; +import VolunteerGroupViewModal from './VolunteerGroupViewModal'; + +enum ModalState { + SAME = 'same', + DELETE = 'delete', + VIEW = 'view', +} + +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', + }, +}; + +/** + * Component for managing volunteer groups for an event. + * This component allows users to view, filter, sort, and create action items. It also provides a modal for creating and editing action items. + * @returns The rendered component. + */ +function volunteerGroups(): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'eventVolunteers', + }); + const { t: tCommon } = useTranslation('common'); + const { t: tErrors } = useTranslation('errors'); + + // Get the organization ID from URL parameters + const { orgId, eventId } = useParams(); + + if (!orgId || !eventId) { + return ; + } + + const [group, setGroup] = useState(null); + const [modalMode, setModalMode] = useState<'create' | 'edit'>('create'); + const [searchValue, setSearchValue] = useState(''); + const [searchTerm, setSearchTerm] = useState(''); + const [sortBy, setSortBy] = useState< + 'volunteers_ASC' | 'volunteers_DESC' | null + >(null); + const [searchBy, setSearchBy] = useState<'leader' | 'group'>('group'); + const [modalState, setModalState] = useState<{ + [key in ModalState]: boolean; + }>({ + [ModalState.SAME]: false, + [ModalState.DELETE]: false, + [ModalState.VIEW]: false, + }); + + /** + * Query to fetch the list of volunteer groups for the event. + */ + const { + data: groupsData, + loading: groupsLoading, + error: groupsError, + refetch: refetchGroups, + }: { + data?: { + getEventVolunteerGroups: InterfaceVolunteerGroupInfo[]; + }; + loading: boolean; + error?: Error | undefined; + refetch: () => void; + } = useQuery(EVENT_VOLUNTEER_GROUP_LIST, { + variables: { + where: { + eventId: eventId, + leaderName: searchBy === 'leader' ? searchTerm : null, + name_contains: searchBy === 'group' ? searchTerm : null, + }, + orderBy: sortBy, + }, + }); + + const openModal = (modal: ModalState): void => + setModalState((prevState) => ({ ...prevState, [modal]: true })); + + const closeModal = (modal: ModalState): void => + setModalState((prevState) => ({ ...prevState, [modal]: false })); + + const handleModalClick = useCallback( + (group: InterfaceVolunteerGroupInfo | null, modal: ModalState): void => { + if (modal === ModalState.SAME) { + setModalMode(group ? 'edit' : 'create'); + } + setGroup(group); + openModal(modal); + }, + [openModal], + ); + + const debouncedSearch = useMemo( + () => debounce((value: string) => setSearchTerm(value), 300), + [], + ); + + const groups = useMemo( + () => groupsData?.getEventVolunteerGroups || [], + [groupsData], + ); + + if (groupsLoading) { + return ; + } + + if (groupsError) { + return ( +
+ +
+ {tErrors('errorLoading', { entity: 'Volunteer Groups' })} +
+
+ ); + } + + const columns: GridColDef[] = [ + { + field: 'group', + headerName: 'Group', + flex: 1, + align: 'left', + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeaders}`, + renderCell: (params: GridCellParams) => { + return ( +
+ {params.row.name} +
+ ); + }, + }, + { + field: 'leader', + headerName: 'Leader', + flex: 1, + align: 'center', + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeaders}`, + renderCell: (params: GridCellParams) => { + const { _id, firstName, lastName, image } = params.row.leader; + return ( +
+ {image ? ( + Assignee + ) : ( +
+ +
+ )} + {firstName + ' ' + lastName} +
+ ); + }, + }, + { + field: 'actions', + headerName: 'Actions Completed', + flex: 1, + align: 'center', + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeaders}`, + renderCell: (params: GridCellParams) => { + return ( +
+ {params.row.assignments.length} +
+ ); + }, + }, + { + field: 'volunteers', + headerName: 'No. of Volunteers', + flex: 1, + align: 'center', + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeaders}`, + renderCell: (params: GridCellParams) => { + return ( +
+ {params.row.volunteers.length} +
+ ); + }, + }, + { + field: 'options', + headerName: 'Options', + align: 'center', + flex: 1, + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeaders}`, + renderCell: (params: GridCellParams) => { + return ( + <> + + + + + ); + }, + }, + ]; + + return ( +
+ {/* Header with search, filter and Create Button */} +
+
+ { + setSearchValue(e.target.value); + debouncedSearch(e.target.value); + }} + data-testid="searchBy" + /> + +
+
+
+ + + + {tCommon('searchBy', { item: '' })} + + + setSearchBy('leader')} + data-testid="leader" + > + {t('leader')} + + setSearchBy('group')} + data-testid="group" + > + {t('group')} + + + + + + + {tCommon('sort')} + + + setSortBy('volunteers_DESC')} + data-testid="volunteers_DESC" + > + {t('mostVolunteers')} + + setSortBy('volunteers_ASC')} + data-testid="volunteers_ASC" + > + {t('leastVolunteers')} + + + +
+
+ +
+
+
+ + {/* Table with Volunteer Groups */} + row._id} + slots={{ + noRowsOverlay: () => ( + + {t('noVolunteerGroups')} + + ), + }} + sx={dataGridStyle} + getRowClassName={() => `${styles.rowBackgrounds}`} + autoHeight + rowHeight={65} + rows={groups.map((group, index) => ({ + id: index + 1, + ...group, + }))} + columns={columns} + isRowSelectable={() => false} + /> + + closeModal(ModalState.SAME)} + refetchGroups={refetchGroups} + eventId={eventId} + orgId={orgId} + group={group} + mode={modalMode} + /> + + {group && ( + <> + closeModal(ModalState.VIEW)} + group={group} + /> + + closeModal(ModalState.DELETE)} + refetchGroups={refetchGroups} + group={group} + /> + + )} +
+ ); +} + +export default volunteerGroups; diff --git a/src/screens/EventVolunteers/Volunteers/VolunteerCreateModal.spec.tsx b/src/screens/EventVolunteers/Volunteers/VolunteerCreateModal.spec.tsx new file mode 100644 index 0000000000..77fe028655 --- /dev/null +++ b/src/screens/EventVolunteers/Volunteers/VolunteerCreateModal.spec.tsx @@ -0,0 +1,129 @@ +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 { + fireEvent, + render, + screen, + waitFor, + within, +} 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 i18n from 'utils/i18nForTest'; +import { MOCKS, MOCKS_ERROR } from './Volunteers.mocks'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import { toast } from 'react-toastify'; +import type { InterfaceVolunteerCreateModal } from './VolunteerCreateModal'; +import VolunteerCreateModal from './VolunteerCreateModal'; +import userEvent from '@testing-library/user-event'; +import { vi } from 'vitest'; + +/** + * Mock implementation of the `react-toastify` module. + * Mocks the `toast` object with `success` and `error` methods to allow testing + * without triggering actual toast notifications. + */ + +vi.mock('react-toastify', () => ({ + toast: { + success: vi.fn(), + error: vi.fn(), + }, +})); + +const link1 = new StaticMockLink(MOCKS); +const link2 = new StaticMockLink(MOCKS_ERROR); +const t = { + ...JSON.parse( + JSON.stringify( + i18n.getDataByLanguage('en')?.translation.eventVolunteers ?? {}, + ), + ), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.common ?? {})), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.errors ?? {})), +}; + +const itemProps: InterfaceVolunteerCreateModal[] = [ + { + isOpen: true, + hide: vi.fn(), + eventId: 'eventId', + orgId: 'orgId', + refetchVolunteers: vi.fn(), + }, +]; + +const renderCreateModal = ( + link: ApolloLink, + props: InterfaceVolunteerCreateModal, +): RenderResult => { + return render( + + + + + + + + + + + , + ); +}; + +describe('Testing VolunteerCreateModal', () => { + it('VolunteerCreateModal -> Create', async () => { + renderCreateModal(link1, itemProps[0]); + expect(screen.getAllByText(t.addVolunteer)).toHaveLength(2); + + // Select Volunteers + const membersSelect = await screen.findByTestId('membersSelect'); + expect(membersSelect).toBeInTheDocument(); + const volunteerInputField = within(membersSelect).getByRole('combobox'); + fireEvent.mouseDown(volunteerInputField); + + const volunteerOption = await screen.findByText('John Doe'); + expect(volunteerOption).toBeInTheDocument(); + fireEvent.click(volunteerOption); + + const submitBtn = screen.getByTestId('submitBtn'); + expect(submitBtn).toBeInTheDocument(); + userEvent.click(submitBtn); + + await waitFor(() => { + expect(toast.success).toHaveBeenCalledWith(t.volunteerAdded); + expect(itemProps[0].refetchVolunteers).toHaveBeenCalled(); + expect(itemProps[0].hide).toHaveBeenCalled(); + }); + }); + + it('VolunteerCreateModal -> Create -> Error', async () => { + renderCreateModal(link2, itemProps[0]); + expect(screen.getAllByText(t.addVolunteer)).toHaveLength(2); + + // Select Volunteers + const membersSelect = await screen.findByTestId('membersSelect'); + expect(membersSelect).toBeInTheDocument(); + const volunteerInputField = within(membersSelect).getByRole('combobox'); + fireEvent.mouseDown(volunteerInputField); + + const volunteerOption = await screen.findByText('John Doe'); + expect(volunteerOption).toBeInTheDocument(); + fireEvent.click(volunteerOption); + + const submitBtn = screen.getByTestId('submitBtn'); + expect(submitBtn).toBeInTheDocument(); + userEvent.click(submitBtn); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalled(); + }); + }); +}); diff --git a/src/screens/EventVolunteers/Volunteers/VolunteerCreateModal.tsx b/src/screens/EventVolunteers/Volunteers/VolunteerCreateModal.tsx new file mode 100644 index 0000000000..dee45376db --- /dev/null +++ b/src/screens/EventVolunteers/Volunteers/VolunteerCreateModal.tsx @@ -0,0 +1,152 @@ +import type { ChangeEvent } from 'react'; +import { Button, Form, Modal } from 'react-bootstrap'; +import type { InterfaceUserInfo } from 'utils/interfaces'; +import styles from '../../../style/app.module.css'; +import React, { useCallback, useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { useMutation, useQuery } from '@apollo/client'; +import { toast } from 'react-toastify'; +import { Autocomplete, TextField } from '@mui/material'; + +import { MEMBERS_LIST } from 'GraphQl/Queries/Queries'; +import { ADD_VOLUNTEER } from 'GraphQl/Mutations/EventVolunteerMutation'; + +export interface InterfaceVolunteerCreateModal { + isOpen: boolean; + hide: () => void; + eventId: string; + orgId: string; + refetchVolunteers: () => void; +} + +/** + * A modal dialog for add a volunteer for an event. + * + * @param isOpen - Indicates whether the modal is open. + * @param hide - Function to close the modal. + * @param eventId - The ID of the event associated with volunteer. + * @param orgId - The ID of the organization associated with volunteer. + * @param refetchVolunteers - Function to refetch the volunteers after adding a volunteer. + * + * @returns The rendered modal component. + * + * The `VolunteerCreateModal` component displays a form within a modal dialog for adding a volunteer. + * It includes fields for selecting user. + * + * The modal includes: + * - A header with a title and a close button. + * - A form with: + * - A multi-select dropdown for selecting user be added as volunteer. + * - A submit button to create or update the pledge. + * + * On form submission, the component: + * - Calls `addVolunteer` mutation to add a new Volunteer. + * + * Success or error messages are displayed using toast notifications based on the result of the mutation. + */ + +const VolunteerCreateModal: React.FC = ({ + isOpen, + hide, + eventId, + orgId, + refetchVolunteers, +}) => { + const { t } = useTranslation('translation', { + keyPrefix: 'eventVolunteers', + }); + + const [userId, setUserId] = useState(''); + const [members, setMembers] = useState([]); + const [addVolunteer] = useMutation(ADD_VOLUNTEER); + + const { data: memberData } = useQuery(MEMBERS_LIST, { + variables: { id: orgId }, + }); + + useEffect(() => { + if (memberData) { + setMembers(memberData.organizations[0].members); + } + }, [memberData]); + + // Function to add a volunteer for an event + const addVolunteerHandler = useCallback( + async (e: ChangeEvent): Promise => { + try { + e.preventDefault(); + await addVolunteer({ + variables: { + data: { + eventId, + userId, + }, + }, + }); + + toast.success(t('volunteerAdded')); + refetchVolunteers(); + setUserId(''); + hide(); + } catch (error: unknown) { + toast.error((error as Error).message); + } + }, + [userId, eventId], + ); + + return ( + + +

{t('addVolunteer')}

+ +
+ +
+ {/* A Multi-select dropdown enables admin to invite a member as volunteer */} + + option._id === value._id} + filterSelectedOptions={true} + getOptionLabel={(member: InterfaceUserInfo): string => + `${member.firstName} ${member.lastName}` + } + onChange={ + /*istanbul ignore next*/ + (_, newVolunteer): void => { + setUserId(newVolunteer?._id ?? ''); + } + } + renderInput={(params) => } + /> + + + {/* Button to submit the volunteer form */} + +
+
+
+ ); +}; +export default VolunteerCreateModal; diff --git a/src/screens/EventVolunteers/Volunteers/VolunteerDeleteModal.spec.tsx b/src/screens/EventVolunteers/Volunteers/VolunteerDeleteModal.spec.tsx new file mode 100644 index 0000000000..575670a887 --- /dev/null +++ b/src/screens/EventVolunteers/Volunteers/VolunteerDeleteModal.spec.tsx @@ -0,0 +1,136 @@ +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 { 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 i18n from 'utils/i18nForTest'; +import { MOCKS, MOCKS_ERROR } from './Volunteers.mocks'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import { toast } from 'react-toastify'; +import type { InterfaceDeleteVolunteerModal } from './VolunteerDeleteModal'; +import VolunteerDeleteModal from './VolunteerDeleteModal'; +import userEvent from '@testing-library/user-event'; +import { vi } from 'vitest'; + +/** + * Mock implementation of the `react-toastify` module. + * Mocks the `toast` object with `success` and `error` methods to allow testing + * without triggering actual toast notifications. + */ + +vi.mock('react-toastify', () => ({ + toast: { + success: vi.fn(), + error: vi.fn(), + }, +})); + +const link1 = new StaticMockLink(MOCKS); +const link2 = new StaticMockLink(MOCKS_ERROR); +const t = { + ...JSON.parse( + JSON.stringify( + i18n.getDataByLanguage('en')?.translation.eventVolunteers ?? {}, + ), + ), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.common ?? {})), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.errors ?? {})), +}; + +const itemProps: InterfaceDeleteVolunteerModal[] = [ + { + isOpen: true, + hide: vi.fn(), + refetchVolunteers: vi.fn(), + volunteer: { + _id: 'volunteerId1', + hasAccepted: true, + hoursVolunteered: 10, + user: { + _id: 'userId1', + firstName: 'Teresa', + lastName: 'Bradley', + image: null, + }, + assignments: [], + groups: [ + { + _id: 'groupId1', + name: 'group1', + volunteers: [ + { + _id: 'volunteerId1', + }, + ], + }, + ], + }, + }, +]; + +const renderVolunteerDeleteModal = ( + link: ApolloLink, + props: InterfaceDeleteVolunteerModal, +): RenderResult => { + return render( + + + + + + + + + + + , + ); +}; + +describe('Testing Volunteer Delete Modal', () => { + it('Delete Volunteer', async () => { + renderVolunteerDeleteModal(link1, itemProps[0]); + expect(screen.getByText(t.removeVolunteer)).toBeInTheDocument(); + + const yesBtn = screen.getByTestId('deleteyesbtn'); + expect(yesBtn).toBeInTheDocument(); + userEvent.click(yesBtn); + + await waitFor(() => { + expect(itemProps[0].refetchVolunteers).toHaveBeenCalled(); + expect(itemProps[0].hide).toHaveBeenCalled(); + expect(toast.success).toHaveBeenCalledWith(t.volunteerRemoved); + }); + }); + + it('Close Delete Modal', async () => { + renderVolunteerDeleteModal(link1, itemProps[0]); + expect(screen.getByText(t.removeVolunteer)).toBeInTheDocument(); + + const noBtn = screen.getByTestId('deletenobtn'); + expect(noBtn).toBeInTheDocument(); + userEvent.click(noBtn); + + await waitFor(() => { + expect(itemProps[0].hide).toHaveBeenCalled(); + }); + }); + + it('Delete Volunteer -> Error', async () => { + renderVolunteerDeleteModal(link2, itemProps[0]); + expect(screen.getByText(t.removeVolunteer)).toBeInTheDocument(); + + const yesBtn = screen.getByTestId('deleteyesbtn'); + expect(yesBtn).toBeInTheDocument(); + userEvent.click(yesBtn); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalled(); + }); + }); +}); diff --git a/src/screens/EventVolunteers/Volunteers/VolunteerDeleteModal.tsx b/src/screens/EventVolunteers/Volunteers/VolunteerDeleteModal.tsx new file mode 100644 index 0000000000..5c841a2f11 --- /dev/null +++ b/src/screens/EventVolunteers/Volunteers/VolunteerDeleteModal.tsx @@ -0,0 +1,103 @@ +import { Button, Modal } from 'react-bootstrap'; +import styles from '../../../style/app.module.css'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { useMutation } from '@apollo/client'; +import type { InterfaceEventVolunteerInfo } from 'utils/interfaces'; +import { toast } from 'react-toastify'; +import { DELETE_VOLUNTEER } from 'GraphQl/Mutations/EventVolunteerMutation'; + +export interface InterfaceDeleteVolunteerModal { + isOpen: boolean; + hide: () => void; + volunteer: InterfaceEventVolunteerInfo; + refetchVolunteers: () => void; +} + +/** + * A modal dialog for confirming the deletion of a volunteer. + * + * @param isOpen - Indicates whether the modal is open. + * @param hide - Function to close the modal. + * @param volunteer - The volunteer object to be deleted. + * @param refetchVolunteers - Function to refetch the volunteers after deletion. + * + * @returns The rendered modal component. + * + * + * The `VolunteerDeleteModal` component displays a confirmation dialog when a user attempts to delete a volunteer. + * It allows the user to either confirm or cancel the deletion. + * On confirmation, the `deleteVolunteer` mutation is called to remove the pledge from the database, + * and the `refetchVolunteers` function is invoked to update the list of volunteers. + * 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 `deleteVolunteer` mutation is used to perform the deletion operation. + */ + +const VolunteerDeleteModal: React.FC = ({ + isOpen, + hide, + volunteer, + refetchVolunteers, +}) => { + const { t } = useTranslation('translation', { + keyPrefix: 'eventVolunteers', + }); + const { t: tCommon } = useTranslation('common'); + + const [deleteVolunteer] = useMutation(DELETE_VOLUNTEER); + + const deleteHandler = async (): Promise => { + try { + await deleteVolunteer({ + variables: { + id: volunteer._id, + }, + }); + refetchVolunteers(); + hide(); + toast.success(t('volunteerRemoved')); + } catch (error: unknown) { + toast.error((error as Error).message); + } + }; + return ( + <> + + +

{t('removeVolunteer')}

+ +
+ +

{t('removeVolunteerMsg')}

+
+ + + + +
+ + ); +}; +export default VolunteerDeleteModal; diff --git a/src/screens/EventVolunteers/Volunteers/VolunteerViewModal.spec.tsx b/src/screens/EventVolunteers/Volunteers/VolunteerViewModal.spec.tsx new file mode 100644 index 0000000000..e99fb47d20 --- /dev/null +++ b/src/screens/EventVolunteers/Volunteers/VolunteerViewModal.spec.tsx @@ -0,0 +1,102 @@ +import React from 'react'; +import { MockedProvider } from '@apollo/react-testing'; +import { LocalizationProvider } from '@mui/x-date-pickers'; +import type { RenderResult } 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'; +import { store } from 'state/store'; +import i18n from 'utils/i18nForTest'; +import type { InterfaceVolunteerViewModal } from './VolunteerViewModal'; +import VolunteerViewModal from './VolunteerViewModal'; +import { vi } from 'vitest'; + +const t = { + ...JSON.parse( + JSON.stringify( + i18n.getDataByLanguage('en')?.translation.eventVolunteers ?? {}, + ), + ), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.common ?? {})), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.errors ?? {})), +}; + +const itemProps: InterfaceVolunteerViewModal[] = [ + { + isOpen: true, + hide: vi.fn(), + volunteer: { + _id: 'volunteerId1', + hasAccepted: true, + hoursVolunteered: 10, + user: { + _id: 'userId1', + firstName: 'Teresa', + lastName: 'Bradley', + image: null, + }, + assignments: [], + groups: [ + { + _id: 'groupId1', + name: 'group1', + volunteers: [ + { + _id: 'volunteerId1', + }, + ], + }, + ], + }, + }, + { + isOpen: true, + hide: vi.fn(), + volunteer: { + _id: 'volunteerId2', + hasAccepted: false, + hoursVolunteered: null, + user: { + _id: 'userId3', + firstName: 'Bruce', + lastName: 'Graza', + image: 'img-url', + }, + assignments: [], + groups: [], + }, + }, +]; + +const renderVolunteerViewModal = ( + props: InterfaceVolunteerViewModal, +): RenderResult => { + return render( + + + + + + + + + + + , + ); +}; + +describe('Testing VolunteerViewModal', () => { + it('Render VolunteerViewModal (variation 1)', async () => { + renderVolunteerViewModal(itemProps[0]); + expect(screen.getByText(t.volunteerDetails)).toBeInTheDocument(); + expect(screen.getByTestId('volunteer_avatar')).toBeInTheDocument(); + }); + + it('Render VolunteerViewModal (variation 2)', async () => { + renderVolunteerViewModal(itemProps[1]); + expect(screen.getByText(t.volunteerDetails)).toBeInTheDocument(); + expect(screen.getByTestId('volunteer_image')).toBeInTheDocument(); + }); +}); diff --git a/src/screens/EventVolunteers/Volunteers/VolunteerViewModal.tsx b/src/screens/EventVolunteers/Volunteers/VolunteerViewModal.tsx new file mode 100644 index 0000000000..830bacf8cc --- /dev/null +++ b/src/screens/EventVolunteers/Volunteers/VolunteerViewModal.tsx @@ -0,0 +1,202 @@ +import { Button, Form, Modal } from 'react-bootstrap'; +import type { InterfaceEventVolunteerInfo } from 'utils/interfaces'; +import styles from '../../../style/app.module.css'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { + FormControl, + Paper, + Table, + TableBody, + TableCell, + TableContainer, + TableHead, + TableRow, + TextField, +} from '@mui/material'; +import Avatar from 'components/Avatar/Avatar'; +import { HistoryToggleOff, TaskAlt } from '@mui/icons-material'; + +export interface InterfaceVolunteerViewModal { + isOpen: boolean; + hide: () => void; + volunteer: InterfaceEventVolunteerInfo; +} + +/** + * A modal dialog for viewing volunteer information for an event. + * + * @param isOpen - Indicates whether the modal is open. + * @param hide - Function to close the modal. + * @param volunteer - The volunteer object to be displayed. + * + * @returns The rendered modal component. + * + * The `VolunteerViewModal` component displays all the fields of a volunteer in a modal dialog. + * + * The modal includes: + * - A header with a title and a close button. + * - fields for volunteer name, status, hours volunteered, groups, and assignments. + */ + +const VolunteerViewModal: React.FC = ({ + isOpen, + hide, + volunteer, +}) => { + const { t } = useTranslation('translation', { + keyPrefix: 'eventVolunteers', + }); + const { t: tCommon } = useTranslation('common'); + + const { user, hasAccepted, hoursVolunteered, groups } = volunteer; + + return ( + + +

{t('volunteerDetails')}

+ +
+ +
+ {/* Volunteer Name & Avatar */} + + + + {user.image ? ( + Volunteer + ) : ( +
+ +
+ )} + + ), + }} + /> +
+
+ {/* Status and hours volunteered */} + + + {hasAccepted ? ( + + ) : ( + + )} + + ), + style: { + color: hasAccepted ? 'green' : '#ed6c02', + }, + }} + inputProps={{ + style: { + WebkitTextFillColor: hasAccepted ? 'green' : '#ed6c02', + }, + }} + disabled + /> + + + + {/* Table for Associated Volunteer Groups */} + {groups && groups.length > 0 && ( + + + Volunteer Groups Joined + + + + + + + Sr. No. + Group Name + + No. of Members + + + + + {groups.map((group, index) => { + const { _id, name, volunteers } = group; + return ( + + + {index + 1} + + + {name} + + + {volunteers.length} + + + ); + })} + +
+
+
+ )} +
+
+
+ ); +}; +export default VolunteerViewModal; diff --git a/src/screens/EventVolunteers/Volunteers/Volunteers.mocks.ts b/src/screens/EventVolunteers/Volunteers/Volunteers.mocks.ts new file mode 100644 index 0000000000..72c927b8ff --- /dev/null +++ b/src/screens/EventVolunteers/Volunteers/Volunteers.mocks.ts @@ -0,0 +1,303 @@ +import { + ADD_VOLUNTEER, + DELETE_VOLUNTEER, +} from 'GraphQl/Mutations/EventVolunteerMutation'; +import { EVENT_VOLUNTEER_LIST } from 'GraphQl/Queries/EventVolunteerQueries'; +import { MEMBERS_LIST } from 'GraphQl/Queries/Queries'; + +const volunteer1 = { + _id: 'volunteerId1', + hasAccepted: true, + hoursVolunteered: 10, + user: { + _id: 'userId1', + firstName: 'Teresa', + lastName: 'Bradley', + image: null, + }, + assignments: [], + groups: [ + { + _id: 'groupId1', + name: 'group1', + volunteers: [ + { + _id: 'volunteerId1', + }, + ], + }, + ], +}; + +const volunteer2 = { + _id: 'volunteerId2', + hasAccepted: false, + hoursVolunteered: null, + user: { + _id: 'userId3', + firstName: 'Bruce', + lastName: 'Graza', + image: 'img-url', + }, + assignments: [], + groups: [], +}; + +export const MOCKS = [ + { + request: { + query: EVENT_VOLUNTEER_LIST, + variables: { + where: { eventId: 'eventId', name_contains: '' }, + orderBy: null, + }, + }, + result: { + data: { + getEventVolunteers: [volunteer1, volunteer2], + }, + }, + }, + { + request: { + query: EVENT_VOLUNTEER_LIST, + variables: { + where: { eventId: 'eventId', name_contains: '' }, + orderBy: 'hoursVolunteered_ASC', + }, + }, + result: { + data: { + getEventVolunteers: [volunteer2, volunteer1], + }, + }, + }, + { + request: { + query: EVENT_VOLUNTEER_LIST, + variables: { + where: { eventId: 'eventId', name_contains: '' }, + orderBy: 'hoursVolunteered_DESC', + }, + }, + result: { + data: { + getEventVolunteers: [volunteer1, volunteer2], + }, + }, + }, + { + request: { + query: EVENT_VOLUNTEER_LIST, + variables: { + where: { eventId: 'eventId', name_contains: 'T' }, + orderBy: null, + }, + }, + result: { + data: { + getEventVolunteers: [volunteer1], + }, + }, + }, + { + request: { + query: EVENT_VOLUNTEER_LIST, + variables: { + where: { eventId: 'eventId', name_contains: '', hasAccepted: false }, + orderBy: null, + }, + }, + result: { + data: { + getEventVolunteers: [volunteer2], + }, + }, + }, + { + request: { + query: EVENT_VOLUNTEER_LIST, + variables: { + where: { eventId: 'eventId', name_contains: '', hasAccepted: false }, + orderBy: null, + }, + }, + result: { + data: { + getEventVolunteers: [volunteer2], + }, + }, + }, + { + request: { + query: EVENT_VOLUNTEER_LIST, + variables: { + where: { eventId: 'eventId', name_contains: '', hasAccepted: true }, + orderBy: null, + }, + }, + result: { + data: { + getEventVolunteers: [volunteer1], + }, + }, + }, + { + request: { + query: DELETE_VOLUNTEER, + variables: { + id: 'volunteerId1', + }, + }, + result: { + data: { + removeEventVolunteer: { + _id: 'volunteerId1', + }, + }, + }, + }, + { + request: { + query: MEMBERS_LIST, + variables: { + id: 'orgId', + }, + }, + result: { + data: { + organizations: [ + { + _id: 'orgId', + members: [ + { + _id: 'userId2', + firstName: 'Harve', + lastName: 'Lance', + email: 'harve@example.com', + image: '', + organizationsBlockedBy: [], + createdAt: '2024-02-14', + }, + { + _id: 'userId3', + firstName: 'John', + lastName: 'Doe', + email: 'johndoe@example.com', + image: '', + organizationsBlockedBy: [], + createdAt: '2024-02-14', + }, + ], + }, + ], + }, + }, + }, + { + request: { + query: ADD_VOLUNTEER, + variables: { + data: { + eventId: 'eventId', + userId: 'userId3', + }, + }, + }, + result: { + data: { + createEventVolunteer: { + _id: 'volunteerId1', + }, + }, + }, + }, +]; + +export const MOCKS_ERROR = [ + { + request: { + query: EVENT_VOLUNTEER_LIST, + variables: { + where: { eventId: 'eventId', name_contains: '' }, + orderBy: null, + }, + }, + error: new Error('An error occurred'), + }, + { + request: { + query: DELETE_VOLUNTEER, + variables: { + id: 'volunteerId1', + }, + }, + error: new Error('An error occurred'), + }, + { + request: { + query: MEMBERS_LIST, + variables: { + id: 'orgId', + }, + }, + result: { + data: { + organizations: [ + { + _id: 'orgId', + members: [ + { + _id: 'userId2', + firstName: 'Harve', + lastName: 'Lance', + email: 'harve@example.com', + image: '', + organizationsBlockedBy: [], + createdAt: '2024-02-14', + }, + { + _id: 'userId3', + firstName: 'John', + lastName: 'Doe', + email: 'johndoe@example.com', + image: '', + organizationsBlockedBy: [], + createdAt: '2024-02-14', + }, + ], + }, + ], + }, + }, + }, + { + request: { + query: ADD_VOLUNTEER, + variables: { + data: { + eventId: 'eventId', + userId: 'userId3', + }, + }, + }, + error: new Error('An error occurred'), + }, +]; + +export const MOCKS_EMPTY = [ + { + request: { + query: EVENT_VOLUNTEER_LIST, + variables: { + where: { eventId: 'eventId', name_contains: '' }, + orderBy: null, + }, + }, + result: { + data: { + getEventVolunteers: [], + }, + }, + }, +]; diff --git a/src/screens/EventVolunteers/Volunteers/Volunteers.spec.tsx b/src/screens/EventVolunteers/Volunteers/Volunteers.spec.tsx new file mode 100644 index 0000000000..be08ec61fb --- /dev/null +++ b/src/screens/EventVolunteers/Volunteers/Volunteers.spec.tsx @@ -0,0 +1,297 @@ +import React, { act } 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 { 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, useParams } from 'react-router-dom'; +import { store } from 'state/store'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import i18n from 'utils/i18nForTest'; +import Volunteers from './Volunteers'; +import type { ApolloLink } from '@apollo/client'; +import { MOCKS, MOCKS_EMPTY, MOCKS_ERROR } from './Volunteers.mocks'; +import { vi } from 'vitest'; + +const link1 = new StaticMockLink(MOCKS); +const link2 = new StaticMockLink(MOCKS_ERROR); +const link3 = new StaticMockLink(MOCKS_EMPTY); +const t = { + ...JSON.parse( + JSON.stringify( + i18n.getDataByLanguage('en')?.translation.eventVolunteers ?? {}, + ), + ), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.common ?? {})), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.errors ?? {})), +}; + +const debounceWait = async (ms = 300): Promise => { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +}; + +const renderVolunteers = (link: ApolloLink): RenderResult => { + return render( + + + + + + + } /> +
} + /> + + + +
+ +
, + ); +}; + +/** Mock useParams to provide consistent test data */ + +describe('Testing Volunteers Screen', () => { + beforeAll(() => { + vi.mock('react-router-dom', async () => { + const actualDom = await vi.importActual('react-router-dom'); + return { + ...actualDom, + useParams: vi.fn(), + }; + }); + }); + + afterAll(() => { + vi.clearAllMocks(); + }); + + it('should redirect to fallback URL if URL params are undefined', async () => { + vi.mocked(useParams).mockReturnValue({ orgId: '', eventId: '' }); + render( + + + + + + } /> + } + /> + + + + + , + ); + + await waitFor(() => { + expect(screen.getByTestId('paramsError')).toBeInTheDocument(); + }); + }); + + it('should render Volunteers screen', async () => { + vi.mocked(useParams).mockReturnValue({ + orgId: 'orgId', + eventId: 'eventId', + }); + + renderVolunteers(link1); + const searchInput = await screen.findByTestId('searchBy'); + expect(searchInput).toBeInTheDocument(); + }); + + it('Check Sorting Functionality', async () => { + vi.mocked(useParams).mockReturnValue({ + orgId: 'orgId', + eventId: 'eventId', + }); + renderVolunteers(link1); + const searchInput = await screen.findByTestId('searchBy'); + expect(searchInput).toBeInTheDocument(); + + let sortBtn = await screen.findByTestId('sort'); + expect(sortBtn).toBeInTheDocument(); + + // Sort by hoursVolunteered_DESC + fireEvent.click(sortBtn); + const hoursVolunteeredDESC = await screen.findByTestId( + 'hoursVolunteered_DESC', + ); + expect(hoursVolunteeredDESC).toBeInTheDocument(); + fireEvent.click(hoursVolunteeredDESC); + + let volunteerName = await screen.findAllByTestId('volunteerName'); + expect(volunteerName[0]).toHaveTextContent('Teresa Bradley'); + + // Sort by hoursVolunteered_ASC + sortBtn = await screen.findByTestId('sort'); + expect(sortBtn).toBeInTheDocument(); + fireEvent.click(sortBtn); + const hoursVolunteeredASC = await screen.findByTestId( + 'hoursVolunteered_ASC', + ); + expect(hoursVolunteeredASC).toBeInTheDocument(); + fireEvent.click(hoursVolunteeredASC); + + volunteerName = await screen.findAllByTestId('volunteerName'); + expect(volunteerName[0]).toHaveTextContent('Bruce Graza'); + }); + + it('Filter Volunteers by status (All)', async () => { + vi.mocked(useParams).mockReturnValue({ + orgId: 'orgId', + eventId: 'eventId', + }); + renderVolunteers(link1); + + 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')); + + const volunteerName = await screen.findAllByTestId('volunteerName'); + expect(volunteerName).toHaveLength(2); + }); + + it('Filter Volunteers by status (Pending)', async () => { + vi.mocked(useParams).mockReturnValue({ + orgId: 'orgId', + eventId: 'eventId', + }); + renderVolunteers(link1); + + const filterBtn = await screen.findByTestId('filter'); + expect(filterBtn).toBeInTheDocument(); + + // Filter by Pending + fireEvent.click(filterBtn); + await waitFor(() => { + expect(screen.getByTestId('statusPending')).toBeInTheDocument(); + }); + fireEvent.click(screen.getByTestId('statusPending')); + + const volunteerName = await screen.findAllByTestId('volunteerName'); + expect(volunteerName[0]).toHaveTextContent('Bruce Graza'); + }); + + it('Filter Volunteers by status (Accepted)', async () => { + vi.mocked(useParams).mockReturnValue({ + orgId: 'orgId', + eventId: 'eventId', + }); + renderVolunteers(link1); + + const filterBtn = await screen.findByTestId('filter'); + expect(filterBtn).toBeInTheDocument(); + + // Filter by Accepted + fireEvent.click(filterBtn); + await waitFor(() => { + expect(screen.getByTestId('statusAccepted')).toBeInTheDocument(); + }); + fireEvent.click(screen.getByTestId('statusAccepted')); + + const volunteerName = await screen.findAllByTestId('volunteerName'); + expect(volunteerName[0]).toHaveTextContent('Teresa Bradley'); + }); + + it('Search', async () => { + vi.mocked(useParams).mockReturnValue({ + orgId: 'orgId', + eventId: 'eventId', + }); + renderVolunteers(link1); + const searchInput = await screen.findByTestId('searchBy'); + expect(searchInput).toBeInTheDocument(); + + userEvent.type(searchInput, 'T'); + await debounceWait(); + + const volunteerName = await screen.findAllByTestId('volunteerName'); + expect(volunteerName[0]).toHaveTextContent('Teresa Bradley'); + }); + + it('should render screen with No Volunteers', async () => { + vi.mocked(useParams).mockReturnValue({ + orgId: 'orgId', + eventId: 'eventId', + }); + renderVolunteers(link3); + + await waitFor(() => { + expect(screen.getByTestId('searchBy')).toBeInTheDocument(); + expect(screen.getByText(t.noVolunteers)).toBeInTheDocument(); + }); + }); + + it('Error while fetching volunteers data', async () => { + vi.mocked(useParams).mockReturnValue({ + orgId: 'orgId', + eventId: 'eventId', + }); + renderVolunteers(link2); + + await waitFor(() => { + expect(screen.getByTestId('errorMsg')).toBeInTheDocument(); + }); + }); + + it('Open and close Volunteer Modal (View)', async () => { + vi.mocked(useParams).mockReturnValue({ + orgId: 'orgId', + eventId: 'eventId', + }); + renderVolunteers(link1); + + const viewItemBtn = await screen.findAllByTestId('viewItemBtn'); + userEvent.click(viewItemBtn[0]); + + expect(await screen.findByText(t.volunteerDetails)).toBeInTheDocument(); + userEvent.click(await screen.findByTestId('modalCloseBtn')); + }); + + it('Open and Close Volunteer Modal (Delete)', async () => { + vi.mocked(useParams).mockReturnValue({ + orgId: 'orgId', + eventId: 'eventId', + }); + renderVolunteers(link1); + + const deleteItemBtn = await screen.findAllByTestId('deleteItemBtn'); + userEvent.click(deleteItemBtn[0]); + + expect(await screen.findByText(t.removeVolunteer)).toBeInTheDocument(); + userEvent.click(await screen.findByTestId('modalCloseBtn')); + }); + + it('Open and close Volunteer Modal (Create)', async () => { + vi.mocked(useParams).mockReturnValue({ + orgId: 'orgId', + eventId: 'eventId', + }); + renderVolunteers(link1); + + const addVolunteerBtn = await screen.findByTestId('addVolunteerBtn'); + userEvent.click(addVolunteerBtn); + + expect(await screen.findAllByText(t.addVolunteer)).toHaveLength(2); + userEvent.click(await screen.findByTestId('modalCloseBtn')); + }); +}); diff --git a/src/screens/EventVolunteers/Volunteers/Volunteers.tsx b/src/screens/EventVolunteers/Volunteers/Volunteers.tsx new file mode 100644 index 0000000000..875431ad6f --- /dev/null +++ b/src/screens/EventVolunteers/Volunteers/Volunteers.tsx @@ -0,0 +1,462 @@ +import React, { useCallback, useMemo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Button, Dropdown, Form } from 'react-bootstrap'; +import { Navigate, useParams } from 'react-router-dom'; + +import { + Circle, + FilterAltOutlined, + Search, + Sort, + WarningAmberRounded, +} from '@mui/icons-material'; + +import { useQuery } from '@apollo/client'; +import Loader from 'components/Loader/Loader'; +import { + DataGrid, + type GridCellParams, + type GridColDef, +} from '@mui/x-data-grid'; +import { Chip, debounce, Stack } from '@mui/material'; +import Avatar from 'components/Avatar/Avatar'; +import styles from '../../../style/app.module.css'; +import { EVENT_VOLUNTEER_LIST } from 'GraphQl/Queries/EventVolunteerQueries'; +import type { InterfaceEventVolunteerInfo } from 'utils/interfaces'; +import VolunteerCreateModal from './VolunteerCreateModal'; +import VolunteerDeleteModal from './VolunteerDeleteModal'; +import VolunteerViewModal from './VolunteerViewModal'; + +enum VolunteerStatus { + All = 'all', + Pending = 'pending', + Accepted = 'accepted', +} + +enum ModalState { + ADD = 'add', + DELETE = 'delete', + VIEW = 'view', +} + +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', + }, +}; + +/** + * Component for managing and displaying event volunteers realted to an event. + * + * This component allows users to view, filter, sort, and create volunteers. It also handles fetching and displaying related data such as volunteer acceptance status, etc. + * + * @returns The rendered component. + */ +function volunteers(): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'eventVolunteers', + }); + const { t: tCommon } = useTranslation('common'); + const { t: tErrors } = useTranslation('errors'); + + // Get the organization ID from URL parameters + const { orgId, eventId } = useParams(); + + if (!orgId || !eventId) { + return ; + } + + const [volunteer, setVolunteer] = + useState(null); + const [searchValue, setSearchValue] = useState(''); + const [searchTerm, setSearchTerm] = useState(''); + const [sortBy, setSortBy] = useState< + 'hoursVolunteered_ASC' | 'hoursVolunteered_DESC' | null + >(null); + const [status, setStatus] = useState(VolunteerStatus.All); + const [modalState, setModalState] = useState<{ + [key in ModalState]: boolean; + }>({ + [ModalState.ADD]: false, + [ModalState.DELETE]: false, + [ModalState.VIEW]: false, + }); + + const openModal = (modal: ModalState): void => { + setModalState((prevState) => ({ ...prevState, [modal]: true })); + }; + + const closeModal = (modal: ModalState): void => { + setModalState((prevState) => ({ ...prevState, [modal]: false })); + }; + + const handleOpenModal = useCallback( + ( + volunteer: InterfaceEventVolunteerInfo | null, + modalType: ModalState, + ): void => { + setVolunteer(volunteer); + openModal(modalType); + }, + [openModal], + ); + + /** + * Query to fetch event volunteers for the event. + */ + const { + data: volunteersData, + loading: volunteersLoading, + error: volunteersError, + refetch: refetchVolunteers, + }: { + data?: { + getEventVolunteers: InterfaceEventVolunteerInfo[]; + }; + loading: boolean; + error?: Error | undefined; + refetch: () => void; + } = useQuery(EVENT_VOLUNTEER_LIST, { + variables: { + where: { + eventId: eventId, + hasAccepted: + status === VolunteerStatus.All + ? undefined + : status === VolunteerStatus.Accepted, + name_contains: searchTerm, + }, + orderBy: sortBy, + }, + }); + + const debouncedSearch = useMemo( + () => debounce((value: string) => setSearchTerm(value), 300), + [], + ); + + const volunteers = useMemo( + () => volunteersData?.getEventVolunteers || [], + [volunteersData], + ); + + if (volunteersLoading) { + return ; + } + + if (volunteersError) { + return ( +
+ +
+ {tErrors('errorLoading', { entity: 'Volunteers' })} +
+
+ ); + } + + const columns: GridColDef[] = [ + { + field: 'volunteer', + headerName: 'Volunteer', + flex: 1, + align: 'center', + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeaders}`, + renderCell: (params: GridCellParams) => { + const { _id, firstName, lastName, image } = params.row.user; + return ( +
+ {image ? ( + volunteer + ) : ( +
+ +
+ )} + {firstName + ' ' + lastName} +
+ ); + }, + }, + { + field: 'status', + headerName: 'Status', + flex: 1, + align: 'center', + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeaders}`, + renderCell: (params: GridCellParams) => { + return ( + } + label={params.row.hasAccepted ? 'Accepted' : 'Pending'} + variant="outlined" + color="primary" + className={`${styles.chip} ${params.row.hasAccepted ? styles.active : styles.pending}`} + /> + ); + }, + }, + { + field: 'hours', + headerName: 'Hours Volunteered', + flex: 1, + align: 'center', + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeaders}`, + renderCell: (params: GridCellParams) => { + return ( +
+ {params.row.hoursVolunteered ?? '-'} +
+ ); + }, + }, + { + field: 'actionItem', + headerName: 'Actions Completed', + align: 'center', + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeaders}`, + flex: 1, + renderCell: (params: GridCellParams) => { + return ( +
+ {params.row.assignments.length} +
+ ); + }, + }, + { + field: 'options', + headerName: 'Options', + align: 'center', + flex: 1, + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeaders}`, + renderCell: (params: GridCellParams) => { + return ( + <> + + + + ); + }, + }, + ]; + + return ( +
+ {/* Header with search, filter and Create Button */} +
+
+ { + setSearchValue(e.target.value); + debouncedSearch(e.target.value); + }} + data-testid="searchBy" + /> + +
+
+
+ + + + {tCommon('sort')} + + + setSortBy('hoursVolunteered_DESC')} + data-testid="hoursVolunteered_DESC" + > + {t('mostHoursVolunteered')} + + setSortBy('hoursVolunteered_ASC')} + data-testid="hoursVolunteered_ASC" + > + {t('leastHoursVolunteered')} + + + + + + + {t('status')} + + + setStatus(VolunteerStatus.All)} + data-testid="statusAll" + > + {tCommon('all')} + + setStatus(VolunteerStatus.Pending)} + data-testid="statusPending" + > + {tCommon('pending')} + + setStatus(VolunteerStatus.Accepted)} + data-testid="statusAccepted" + > + {t('accepted')} + + + +
+
+ +
+
+
+ + {/* Table with Volunteers */} + row._id} + slots={{ + noRowsOverlay: () => ( + + {t('noVolunteers')} + + ), + }} + sx={dataGridStyle} + getRowClassName={() => `${styles.rowBackgrounds}`} + autoHeight + rowHeight={65} + rows={volunteers.map((volunteer, index) => ({ + id: index + 1, + ...volunteer, + }))} + columns={columns} + isRowSelectable={() => false} + /> + + closeModal(ModalState.ADD)} + eventId={eventId} + orgId={orgId} + refetchVolunteers={refetchVolunteers} + /> + + {volunteer && ( + <> + closeModal(ModalState.VIEW)} + volunteer={volunteer} + /> + closeModal(ModalState.DELETE)} + volunteer={volunteer} + refetchVolunteers={refetchVolunteers} + /> + + )} +
+ ); +} + +export default volunteers; diff --git a/src/screens/ForgotPassword/ForgotPassword.module.css b/src/screens/ForgotPassword/ForgotPassword.module.css deleted file mode 100644 index 74e09aecc6..0000000000 --- a/src/screens/ForgotPassword/ForgotPassword.module.css +++ /dev/null @@ -1,71 +0,0 @@ -.pageWrapper { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - height: 100vh; -} - -.cardBody { - padding: 2rem; - background-color: #fff; - border-radius: 0.8rem; - border: 1px solid var(--bs-gray-200); -} - -.keyWrapper { - height: 72px; - width: 72px; - transform: rotate(180deg); - position: relative; - overflow: hidden; - display: block; - display: flex; - justify-content: center; - align-items: center; - border-radius: 50%; - margin: 1rem auto; -} - -.keyWrapper .themeOverlay { - position: absolute; - background-color: var(--bs-primary); - height: 100%; - width: 100%; - opacity: 0.15; -} - -.keyWrapper .keyLogo { - height: 42px; - width: 42px; - -webkit-animation: zoomIn 0.3s ease-in-out; - animation: zoomIn 0.3s ease-in-out; -} - -@-webkit-keyframes zoomIn { - 0% { - opacity: 0; - -webkit-transform: scale(0.5); - transform: scale(0.5); - } - - 100% { - opacity: 1; - -webkit-transform: scale(1); - transform: scale(1); - } -} - -@keyframes zoomIn { - 0% { - opacity: 0; - -webkit-transform: scale(0.5); - transform: scale(0.5); - } - - 100% { - opacity: 1; - -webkit-transform: scale(1); - transform: scale(1); - } -} diff --git a/src/screens/ForgotPassword/ForgotPassword.tsx b/src/screens/ForgotPassword/ForgotPassword.tsx index 663960572b..83f20b4375 100644 --- a/src/screens/ForgotPassword/ForgotPassword.tsx +++ b/src/screens/ForgotPassword/ForgotPassword.tsx @@ -16,7 +16,7 @@ import { Form } from 'react-bootstrap'; import Button from 'react-bootstrap/Button'; import { useTranslation } from 'react-i18next'; import { errorHandler } from 'utils/errorHandler'; -import styles from './ForgotPassword.module.css'; +import styles from 'style/app.module.css'; import useLocalStorage from 'utils/useLocalstorage'; /** @@ -162,7 +162,7 @@ const ForgotPassword = (): JSX.Element => {
-
+
diff --git a/src/screens/FundCampaignPledge/FundCampaignPledge.module.css b/src/screens/FundCampaignPledge/FundCampaignPledge.module.css deleted file mode 100644 index cdf4476267..0000000000 --- a/src/screens/FundCampaignPledge/FundCampaignPledge.module.css +++ /dev/null @@ -1,273 +0,0 @@ -.pledgeContainer { - margin: 0.6rem 0; -} - -.container { - min-height: 100vh; -} - -.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; -} - -.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%; -} -.message { - 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; -} - -.btnsContainer { - display: flex; - gap: 0.8rem; - margin: 2.2rem 0 0.8rem 0; -} - -.btnsContainer .input { - flex: 1; - min-width: 18rem; - position: relative; -} - -.btnsContainer input { - outline: 1px solid var(--bs-gray-400); -} - -.btnsContainer .input button { - width: 52px; -} - -.inputField { - background-color: white; - box-shadow: 0 1px 1px #31bb6b; -} - -.dropdown { - background-color: white; - border: 1px solid #31bb6b; - position: relative; - display: inline-block; - color: #31bb6b; -} - -.tableHeader { - background-color: var(--bs-primary); - color: var(--bs-white); - font-size: 1rem; -} - -.rowBackground { - background-color: var(--bs-white); - max-height: 120px; -} - -.TableImage { - object-fit: cover; - width: 25px !important; - height: 25px !important; - border-radius: 100% !important; -} - -.avatarContainer { - width: 28px; - height: 26px; -} - -.imageContainer { - display: flex; - align-items: center; - justify-content: center; -} - -.pledgerContainer { - display: flex; - align-items: center; - justify-content: center; - margin: 0.1rem 0.25rem; - gap: 0.25rem; - 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.tsx b/src/screens/FundCampaignPledge/FundCampaignPledge.tsx index f7e339dc89..8942265eea 100644 --- a/src/screens/FundCampaignPledge/FundCampaignPledge.tsx +++ b/src/screens/FundCampaignPledge/FundCampaignPledge.tsx @@ -9,7 +9,7 @@ import { Button, Dropdown, Form } from 'react-bootstrap'; import { useTranslation } from 'react-i18next'; import { Navigate, useParams } from 'react-router-dom'; import { currencySymbols } from 'utils/currency'; -import styles from './FundCampaignPledge.module.css'; +import styles from '../../style/app.module.css'; import PledgeDeleteModal from './PledgeDeleteModal'; import PledgeModal from './PledgeModal'; import { Breadcrumbs, Link, Stack, Typography } from '@mui/material'; @@ -18,7 +18,7 @@ import Avatar from 'components/Avatar/Avatar'; import type { GridCellParams, GridColDef } from '@mui/x-data-grid'; import type { InterfacePledgeInfo, - InterfacePledger, + InterfaceUserInfo, InterfaceQueryFundCampaignsPledges, } from 'utils/interfaces'; import ProgressBar from 'react-bootstrap/ProgressBar'; @@ -84,7 +84,7 @@ const fundCampaignPledge = (): JSX.Element => { }); const [anchor, setAnchor] = useState(null); - const [extraUsers, setExtraUsers] = useState([]); + const [extraUsers, setExtraUsers] = useState([]); const [progressIndicator, setProgressIndicator] = useState< 'raised' | 'pledged' >('pledged'); @@ -189,7 +189,7 @@ const fundCampaignPledge = (): JSX.Element => { const handleClick = ( event: React.MouseEvent, - users: InterfacePledger[], + users: InterfaceUserInfo[], ): void => { setExtraUsers(users); setAnchor(anchor ? null : event.currentTarget); @@ -226,21 +226,21 @@ const fundCampaignPledge = (): JSX.Element => {
{params.row.users .slice(0, 2) - .map((user: InterfacePledger, index: number) => ( + .map((user: InterfaceUserInfo, index: number) => (
{user.image ? ( pledge ) : (
@@ -425,14 +425,14 @@ const fundCampaignPledge = (): JSX.Element => { > setProgressIndicator('pledged')} />
-
-
+
+
setSearchTerm(e.target.value)} data-testid="searchPledger" @@ -557,7 +557,7 @@ const fundCampaignPledge = (): JSX.Element => { ), }} sx={dataGridStyle} - getRowClassName={() => `${styles.rowBackground}`} + getRowClassName={() => `${styles.rowBackgroundPledge}`} autoHeight rowHeight={65} rows={pledges.map((pledge) => ({ @@ -596,7 +596,7 @@ const fundCampaignPledge = (): JSX.Element => { disablePortal className={`${styles.popup} ${extraUsers.length > 4 ? styles.popupExtra : ''}`} > - {extraUsers.map((user: InterfacePledger, index: number) => ( + {extraUsers.map((user: InterfaceUserInfo, index: number) => (
{ src={user.image} alt="pledger" data-testid={`extraImage${index + 1}`} - className={styles.TableImage} + className={styles.TableImagePledge} /> ) : (
= ({ pledgeEndDate: new Date(pledge?.endDate ?? new Date()), pledgeStartDate: new Date(pledge?.startDate ?? new Date()), }); - const [pledgers, setPledgers] = useState([]); + const [pledgers, setPledgers] = useState([]); const [updatePledge] = useMutation(UPDATE_PLEDGE); const [createPledge] = useMutation(CREATE_PlEDGE); @@ -228,14 +228,14 @@ const PledgeModal: React.FC = ({ option._id === value._id} filterSelectedOptions={true} - getOptionLabel={(member: InterfacePledger): string => + getOptionLabel={(member: InterfaceUserInfo): string => `${member.firstName} ${member.lastName}` } onChange={ @@ -258,7 +258,7 @@ const PledgeModal: React.FC = ({ format="DD/MM/YYYY" label={tCommon('startDate')} value={dayjs(pledgeStartDate)} - className={styles.noOutline} + className={styles.noOutlinePledge} onChange={(date: Dayjs | null): void => { if (date) { setFormState({ @@ -280,7 +280,7 @@ const PledgeModal: React.FC = ({ { if (date) { @@ -327,7 +327,7 @@ const PledgeModal: React.FC = ({ { if (parseInt(e.target.value) > 0) { @@ -343,7 +343,7 @@ const PledgeModal: React.FC = ({ {/* Button to submit the pledge form */}
} + /> + + + + + + , + ); +}; + +describe('Testing Leaderboard Screen', () => { + beforeAll(() => { + vi.mock('react-router-dom', async () => { + const originalModule = await vi.importActual('react-router-dom'); + return { + ...originalModule, + useParams: vi.fn(), + }; + }); + }); + + afterAll(() => { + vi.clearAllMocks(); + }); + + it('should redirect to fallback URL if URL params are undefined', async () => { + vi.mocked(useParams).mockReturnValue({ orgId: '' }); + render( + + + + + + } /> +
} + /> + + + + + , + ); + await waitFor(() => { + expect(screen.getByTestId('paramsError')).toBeInTheDocument(); + }); + }); + + it('should render Leaderboard screen', async () => { + vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' }); + renderLeaderboard(link1); + + await waitFor(() => { + expect(screen.getByTestId('searchBy')).toBeInTheDocument(); + }); + }); + + it('Check Sorting Functionality', async () => { + vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' }); + renderLeaderboard(link1); + + await waitFor(() => { + expect(screen.getByTestId('searchBy')).toBeInTheDocument(); + }); + + const sortBtn = await screen.findByTestId('sort'); + expect(sortBtn).toBeInTheDocument(); + + // Sort by hours_DESC + fireEvent.click(sortBtn); + const hoursDesc = await screen.findByTestId('hours_DESC'); + expect(hoursDesc).toBeInTheDocument(); + fireEvent.click(hoursDesc); + + let userName = await screen.findAllByTestId('userName'); + expect(userName[0]).toHaveTextContent('Teresa Bradley'); + + // Sort by hours_ASC + expect(sortBtn).toBeInTheDocument(); + fireEvent.click(sortBtn); + const hoursAsc = await screen.findByTestId('hours_ASC'); + expect(hoursAsc).toBeInTheDocument(); + fireEvent.click(hoursAsc); + + userName = await screen.findAllByTestId('userName'); + expect(userName[0]).toHaveTextContent('Jane Doe'); + }); + + it('Check Timeframe filter Functionality (All Time)', async () => { + vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' }); + renderLeaderboard(link1); + + await waitFor(() => { + expect(screen.getByTestId('searchBy')).toBeInTheDocument(); + }); + + // Filter by allTime + const filter = await screen.findByTestId('timeFrame'); + expect(filter).toBeInTheDocument(); + + fireEvent.click(filter); + const timeFrameAll = await screen.findByTestId('timeFrameAll'); + expect(timeFrameAll).toBeInTheDocument(); + + fireEvent.click(timeFrameAll); + const userName = await screen.findAllByTestId('userName'); + expect(userName).toHaveLength(4); + }); + + it('Check Timeframe filter Functionality (Weekly)', async () => { + vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' }); + renderLeaderboard(link1); + + await waitFor(() => { + expect(screen.getByTestId('searchBy')).toBeInTheDocument(); + }); + + const filter = await screen.findByTestId('timeFrame'); + expect(filter).toBeInTheDocument(); + + // Filter by weekly + expect(filter).toBeInTheDocument(); + fireEvent.click(filter); + + const timeFrameWeekly = await screen.findByTestId('timeFrameWeekly'); + expect(timeFrameWeekly).toBeInTheDocument(); + fireEvent.click(timeFrameWeekly); + + const userName = await screen.findAllByTestId('userName'); + expect(userName).toHaveLength(1); + }); + + it('Check Timeframe filter Functionality (Monthly)', async () => { + vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' }); + renderLeaderboard(link1); + + await waitFor(() => { + expect(screen.getByTestId('searchBy')).toBeInTheDocument(); + }); + + // Filter by monthly + const filter = await screen.findByTestId('timeFrame'); + expect(filter).toBeInTheDocument(); + fireEvent.click(filter); + + const timeFrameMonthly = await screen.findByTestId('timeFrameMonthly'); + expect(timeFrameMonthly).toBeInTheDocument(); + fireEvent.click(timeFrameMonthly); + + const userName = await screen.findAllByTestId('userName'); + expect(userName).toHaveLength(2); + }); + + it('Check Timeframe filter Functionality (Yearly)', async () => { + vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' }); + renderLeaderboard(link1); + + await waitFor(() => { + expect(screen.getByTestId('searchBy')).toBeInTheDocument(); + }); + + // Filter by yearly + const filter = await screen.findByTestId('timeFrame'); + expect(filter).toBeInTheDocument(); + fireEvent.click(filter); + + const timeFrameYearly = await screen.findByTestId('timeFrameYearly'); + expect(timeFrameYearly).toBeInTheDocument(); + fireEvent.click(timeFrameYearly); + + const userName = await screen.findAllByTestId('userName'); + expect(userName).toHaveLength(3); + }); + + it('Search Volunteers', async () => { + vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' }); + renderLeaderboard(link1); + + const searchInput = await screen.findByTestId('searchBy'); + expect(searchInput).toBeInTheDocument(); + + // Search by name on press of ENTER + userEvent.type(searchInput, 'T'); + await debounceWait(); + + await waitFor(() => { + const userName = screen.getAllByTestId('userName'); + expect(userName).toHaveLength(1); + }); + }); + + it('OnClick of Member navigate to Member Screen', async () => { + vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' }); + renderLeaderboard(link1); + + const searchInput = await screen.findByTestId('searchBy'); + expect(searchInput).toBeInTheDocument(); + + const userName = screen.getAllByTestId('userName'); + userEvent.click(userName[0]); + + await waitFor(() => { + expect(screen.getByTestId('memberScreen')).toBeInTheDocument(); + }); + }); + + it('should render Leaderboard screen with No Volunteers', async () => { + vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' }); + renderLeaderboard(link3); + + await waitFor(() => { + expect(screen.getByTestId('searchBy')).toBeInTheDocument(); + expect(screen.getByText(t.noVolunteers)).toBeInTheDocument(); + }); + }); + + it('Error while fetching volunteer data', async () => { + vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' }); + renderLeaderboard(link2); + + await waitFor(() => { + expect(screen.getByTestId('errorMsg')).toBeInTheDocument(); + }); + }); +}); diff --git a/src/screens/Leaderboard/Leaderboard.tsx b/src/screens/Leaderboard/Leaderboard.tsx new file mode 100644 index 0000000000..e0ea513e9c --- /dev/null +++ b/src/screens/Leaderboard/Leaderboard.tsx @@ -0,0 +1,372 @@ +import React, { useMemo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Button, Dropdown, Form } from 'react-bootstrap'; +import { Navigate, useNavigate, useParams } from 'react-router-dom'; + +import { + FilterAltOutlined, + Search, + Sort, + WarningAmberRounded, +} from '@mui/icons-material'; +import gold from 'assets/images/gold.png'; +import silver from 'assets/images/silver.png'; +import bronze from 'assets/images/bronze.png'; + +import type { InterfaceVolunteerRank } from 'utils/interfaces'; +import styles from '../../style/app.module.css'; +import Loader from 'components/Loader/Loader'; +import { + DataGrid, + type GridCellParams, + type GridColDef, +} from '@mui/x-data-grid'; +import { debounce, Stack } from '@mui/material'; +import Avatar from 'components/Avatar/Avatar'; +import { VOLUNTEER_RANKING } from 'GraphQl/Queries/EventVolunteerQueries'; +import { useQuery } from '@apollo/client'; + +enum TimeFrame { + All = 'allTime', + Weekly = 'weekly', + Monthly = 'monthly', + Yearly = 'yearly', +} + +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', + }, +}; + +/** + * Component to display the leaderboard of volunteers. + * + * This component shows a leaderboard of volunteers ranked by hours contributed, + * with features for filtering by time frame and sorting by hours. It displays + * volunteer details including rank, name, email, and hours volunteered. + * + * @returns The rendered component. + */ +function leaderboard(): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'leaderboard', + }); + const { t: tCommon } = useTranslation('common'); + const { t: tErrors } = useTranslation('errors'); + + // Get the organization ID from URL parameters + const { orgId } = useParams(); + + if (!orgId) { + return ; + } + + const navigate = useNavigate(); + const [searchValue, setSearchValue] = useState(''); + const [searchTerm, setSearchTerm] = useState(''); + const [sortBy, setSortBy] = useState<'hours_ASC' | 'hours_DESC'>( + 'hours_DESC', + ); + const [timeFrame, setTimeFrame] = useState(TimeFrame.All); + + /** + * Query to fetch volunteer rankings. + */ + const { + data: rankingsData, + loading: rankingsLoading, + error: rankingsError, + }: { + data?: { + getVolunteerRanks: InterfaceVolunteerRank[]; + }; + loading: boolean; + error?: Error | undefined; + } = useQuery(VOLUNTEER_RANKING, { + variables: { + orgId, + where: { + orderBy: sortBy, + timeFrame: timeFrame, + nameContains: searchTerm, + }, + }, + }); + + const debouncedSearch = useMemo( + () => debounce((value: string) => setSearchTerm(value), 300), + [], + ); + + const rankings = useMemo( + () => rankingsData?.getVolunteerRanks || [], + [rankingsData], + ); + + if (rankingsLoading) { + return ; + } + + if (rankingsError) { + return ( +
+ +
+ {tErrors('errorLoading', { entity: 'Volunteer Rankings' })} +
+
+ ); + } + + const columns: GridColDef[] = [ + { + field: 'rank', + headerName: 'Rank', + flex: 1, + align: 'center', + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + if (params.row.rank === 1) { + return ( + <> + gold + + ); + } else if (params.row.rank === 2) { + return ( + <> + silver + + ); + } else if (params.row.rank === 3) { + return ( + <> + bronze + + ); + } else return <>{params.row.rank}; + }, + }, + { + field: 'volunteer', + headerName: 'Volunteer', + flex: 2, + align: 'center', + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + const { _id, firstName, lastName, image } = params.row.user; + + return ( + <> +
+ navigate(`/member/${orgId}`, { state: { id: _id } }) + } + data-testid="userName" + > + {image ? ( + User + ) : ( +
+ +
+ )} + {firstName + ' ' + lastName} +
+ + ); + }, + }, + { + field: 'email', + headerName: 'Email', + flex: 2, + align: 'center', + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + return ( +
+ {params.row.user.email} +
+ ); + }, + }, + { + field: 'hoursVolunteered', + headerName: 'Hours Volunteered', + flex: 2, + align: 'center', + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + return
{params.row.hoursVolunteered}
; + }, + }, + ]; + + return ( +
+ {/* Header with search, filter and Create Button */} +
+
+ { + setSearchValue(e.target.value); + debouncedSearch(e.target.value); + }} + data-testid="searchBy" + /> + +
+
+
+ + + + {tCommon('sort')} + + + setSortBy('hours_DESC')} + data-testid="hours_DESC" + > + {t('mostHours')} + + setSortBy('hours_ASC')} + data-testid="hours_ASC" + > + {t('leastHours')} + + + + + + + {t('timeFrame')} + + + setTimeFrame(TimeFrame.All)} + data-testid="timeFrameAll" + > + {t('allTime')} + + setTimeFrame(TimeFrame.Weekly)} + data-testid="timeFrameWeekly" + > + {t('weekly')} + + setTimeFrame(TimeFrame.Monthly)} + data-testid="timeFrameMonthly" + > + {t('monthly')} + + setTimeFrame(TimeFrame.Yearly)} + data-testid="timeFrameYearly" + > + {t('yearly')} + + + +
+
+
+ + {/* Table with Action Items */} + row.user._id} + slots={{ + noRowsOverlay: () => ( + + {t('noVolunteers')} + + ), + }} + sx={dataGridStyle} + getRowClassName={() => `${styles.rowBackground}`} + autoHeight + rowHeight={65} + rows={rankings.map((ranking, index) => ({ + id: index + 1, + ...ranking, + }))} + columns={columns} + isRowSelectable={() => false} + /> +
+ ); +} + +export default leaderboard; diff --git a/src/screens/LoginPage/LoginPage.module.css b/src/screens/LoginPage/LoginPage.module.css deleted file mode 100644 index e7ce0eca7e..0000000000 --- a/src/screens/LoginPage/LoginPage.module.css +++ /dev/null @@ -1,235 +0,0 @@ -.login_background { - min-height: 100vh; -} - -.communityLogo { - object-fit: contain; -} - -.row .left_portion { - display: flex; - justify-content: center; - align-items: center; - flex-direction: column; - height: 100vh; -} - -.selectOrgText input { - outline: none !important; -} - -.row .left_portion .inner .palisadoes_logo { - width: 600px; - height: auto; -} - -.row .right_portion { - min-height: 100vh; - position: relative; - overflow-y: scroll; - display: flex; - flex-direction: column; - justify-content: center; - padding: 1rem 2.5rem; - background: var(--bs-white); -} - -.row .right_portion::-webkit-scrollbar { - display: none; -} - -.row .right_portion .langChangeBtn { - margin: 0; - position: absolute; - top: 1rem; - left: 1rem; -} - -.langChangeBtnStyle { - width: 7.5rem; - height: 2.2rem; - padding: 0; -} - -.row .right_portion .talawa_logo { - height: 5rem; - width: 5rem; - display: block; - margin: 1.5rem auto 1rem; - -webkit-animation: zoomIn 0.3s ease-in-out; - animation: zoomIn 0.3s ease-in-out; -} - -.row .orText { - display: block; - position: absolute; - top: 0; - left: calc(50% - 2.6rem); - margin: 0 auto; - padding: 0.35rem 2rem; - z-index: 100; - background: var(--bs-white); - color: var(--bs-secondary); -} - -@media (max-width: 992px) { - .row .left_portion { - padding: 0 2rem; - } - - .row .left_portion .inner .palisadoes_logo { - width: 100%; - } -} - -@media (max-width: 769px) { - .row { - flex-direction: column-reverse; - } - - .row .right_portion, - .row .left_portion { - height: unset; - } - - .row .right_portion { - min-height: 100vh; - overflow-y: unset; - } - - .row .left_portion .inner { - display: flex; - justify-content: center; - } - - .row .left_portion .inner .palisadoes_logo { - height: 70px; - width: unset; - position: absolute; - margin: 0.5rem; - top: 0; - right: 0; - z-index: 100; - } - - .row .left_portion .inner p { - margin-bottom: 0; - padding: 1rem; - } - - .socialIcons { - margin-bottom: 1rem; - } -} - -@media (max-width: 577px) { - .row .right_portion { - padding: 1rem 1rem 0 1rem; - } - - .row .right_portion .langChangeBtn { - position: absolute; - margin: 1rem; - left: 0; - top: 0; - } - - .marginTopForReg { - margin-top: 4rem !important; - } - - .row .right_portion .talawa_logo { - height: 120px; - margin: 0 auto 2rem auto; - } - - .socialIcons { - margin-bottom: 1rem; - } -} - -.active_tab { - -webkit-animation: fadeIn 0.3s ease-in-out; - animation: fadeIn 0.3s ease-in-out; -} - -@-webkit-keyframes zoomIn { - 0% { - opacity: 0; - -webkit-transform: scale(0.5); - transform: scale(0.5); - } - - 100% { - opacity: 1; - -webkit-transform: scale(1); - transform: scale(1); - } -} - -@keyframes zoomIn { - 0% { - opacity: 0; - -webkit-transform: scale(0.5); - transform: scale(0.5); - } - - 100% { - opacity: 1; - -webkit-transform: scale(1); - transform: scale(1); - } -} - -@-webkit-keyframes fadeIn { - 0% { - opacity: 0; - -webkit-transform: translateY(2rem); - transform: translateY(2rem); - } - - 100% { - opacity: 1; - -webkit-transform: translateY(0); - transform: translateY(0); - } -} - -@keyframes fadeIn { - 0% { - opacity: 0; - -webkit-transform: translateY(2rem); - transform: translateY(2rem); - } - - 100% { - opacity: 1; - -webkit-transform: translateY(0); - transform: translateY(0); - } -} - -.socialIcons { - display: flex; - gap: 16px; - justify-content: center; -} - -.password_checks { - display: flex; - justify-content: space-between; - align-items: flex-start; - flex-direction: column; -} - -.password_check_element { - margin-top: -10px; -} - -.password_check_element_top { - margin-top: 18px; -} - -.password_check_element_bottom { - margin-bottom: -20px; -} diff --git a/src/screens/LoginPage/LoginPage.test.tsx b/src/screens/LoginPage/LoginPage.spec.tsx similarity index 80% rename from src/screens/LoginPage/LoginPage.test.tsx rename to src/screens/LoginPage/LoginPage.spec.tsx index 3733a454dd..242f00f2b2 100644 --- a/src/screens/LoginPage/LoginPage.test.tsx +++ b/src/screens/LoginPage/LoginPage.spec.tsx @@ -1,12 +1,16 @@ import React, { act } from 'react'; import { MockedProvider } from '@apollo/react-testing'; -import { render, screen, fireEvent, within } from '@testing-library/react'; +import { + render, + screen, + fireEvent, + within, + waitFor, +} 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 'jest-localstorage-mock'; -import 'jest-location-mock'; import { StaticMockLink } from 'utils/StaticMockLink'; import LoginPage from './LoginPage'; import { @@ -19,7 +23,7 @@ import i18nForTest from 'utils/i18nForTest'; import { BACKEND_URL } from 'Constant/constant'; import useLocalStorage from 'utils/useLocalstorage'; import { GET_COMMUNITY_DATA, ORGANIZATION_LIST } from 'GraphQl/Queries/Queries'; -import { debug } from 'jest-preview'; +import { vi, beforeEach, expect, it, describe } from 'vitest'; const MOCKS = [ { @@ -50,8 +54,8 @@ const MOCKS = [ request: { query: SIGNUP_MUTATION, variables: { - firstName: 'John', - lastName: 'Doe', + firstName: 'John Patrick ', + lastName: 'Doe ', email: 'johndoe@gmail.com', password: 'johnDoe', }, @@ -208,28 +212,29 @@ async function wait(ms = 100): Promise { }); } -jest.mock('react-toastify', () => ({ +vi.mock('react-toastify', () => ({ toast: { - success: jest.fn(), - warn: jest.fn(), - error: jest.fn(), + success: vi.fn(), + warn: vi.fn(), + error: vi.fn(), }, })); -jest.mock('Constant/constant.ts', () => ({ - ...jest.requireActual('Constant/constant.ts'), +vi.mock('Constant/constant.ts', async () => ({ + ...(await vi.importActual('Constant/constant.ts')), REACT_APP_USE_RECAPTCHA: 'yes', RECAPTCHA_SITE_KEY: 'xxx', })); -const mockNavigate = jest.fn(); -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), +const mockNavigate = vi.fn(); +vi.mock('react-router-dom', async () => ({ + ...(await vi.importActual('react-router-dom')), useNavigate: () => mockNavigate, })); -jest.mock('react-google-recaptcha', () => { - const react = jest.requireActual('react'); +const resetReCAPTCHA = vi.fn(); +vi.mock('react-google-recaptcha', async () => { + const react = await vi.importActual('react'); const recaptcha = react.forwardRef( ( props: { @@ -239,6 +244,12 @@ jest.mock('react-google-recaptcha', () => { ): JSX.Element => { const { onChange, ...otherProps } = props; + Object.defineProperty(ref, 'current', { + value: { + reset: resetReCAPTCHA, + }, + }); + const handleChange = ( event: React.ChangeEvent, ): void => { @@ -260,12 +271,23 @@ jest.mock('react-google-recaptcha', () => { ); }, ); - return recaptcha; + return { + __esModule: true, + default: recaptcha, + }; }); describe('Testing Login Page Screen', () => { - test('Component Should be rendered properly', async () => { - window.location.assign('/orglist'); + it('Component Should be rendered properly', async () => { + Object.defineProperty(window, 'location', { + configurable: true, + value: { + reload: vi.fn(), + href: 'https://localhost:4321/orglist', + origin: 'https://localhost:4321', + pathname: '/orglist', + }, + }); render( @@ -284,10 +306,10 @@ describe('Testing Login Page Screen', () => { userEvent.click(adminLink); await wait(); expect(screen.getByText(/Admin/i)).toBeInTheDocument(); - expect(window.location).toBeAt('/orglist'); + expect(window.location.pathname).toBe('/orglist'); }); - test('There should be default values of pre-login data when queried result is null', async () => { + it('There should be default values of pre-login data when queried result is null', async () => { render( @@ -311,7 +333,7 @@ describe('Testing Login Page Screen', () => { expect(screen.queryAllByTestId('preLoginSocialMedia')[0]).toBeUndefined(); }); - test('There should be a different values of pre-login data if the queried result is not null', async () => { + it('There should be a different values of pre-login data if the queried result is not null', async () => { render( @@ -332,7 +354,7 @@ describe('Testing Login Page Screen', () => { expect(screen.queryAllByTestId('PalisadoesSocialMedia')[0]).toBeUndefined(); }); - test('Testing registration functionality', async () => { + it('Testing registration functionality', async () => { const formData = { firstName: 'John', lastName: 'Doe', @@ -377,7 +399,7 @@ describe('Testing Login Page Screen', () => { userEvent.click(screen.getByTestId('registrationBtn')); }); - test('Testing registration functionality when all inputs are invalid', async () => { + it('Testing registration functionality when all inputs are invalid', async () => { const formData = { firstName: '1234', lastName: '8890', @@ -421,7 +443,7 @@ describe('Testing Login Page Screen', () => { userEvent.click(screen.getByTestId('registrationBtn')); }); - test('Testing registration functionality, when password and confirm password is not same', async () => { + it('Testing registration functionality, when password and confirm password is not same', async () => { const formData = { firstName: 'John', lastName: 'Doe', @@ -464,7 +486,7 @@ describe('Testing Login Page Screen', () => { userEvent.click(screen.getByTestId('registrationBtn')); }); - test('Testing registration functionality, when input is not filled correctly', async () => { + it('Testing registration functionality, when input is not filled correctly', async () => { const formData = { firstName: 'J', lastName: 'D', @@ -507,7 +529,7 @@ describe('Testing Login Page Screen', () => { userEvent.click(screen.getByTestId('registrationBtn')); }); - test('switches to login tab on successful registration', async () => { + it('switches to login tab on successful registration', async () => { const formData = { firstName: 'John', lastName: 'Doe', @@ -555,7 +577,7 @@ describe('Testing Login Page Screen', () => { expect(screen.getByTestId('goToRegisterPortion')).toBeInTheDocument(); }); - test('Testing toggle login register portion', async () => { + it('Testing toggle login register portion', async () => { render( @@ -577,7 +599,7 @@ describe('Testing Login Page Screen', () => { await wait(); }); - test('Testing login functionality', async () => { + it('Testing login functionality', async () => { const formData = { email: 'johndoe@gmail.com', password: 'johndoe', @@ -608,7 +630,87 @@ describe('Testing Login Page Screen', () => { await wait(); }); - test('Testing password preview feature for login', async () => { + it('Testing ReCaptcha functionality, it should refresh on unsuccessful SignUp, using duplicate email', async () => { + const formData = { + firstName: 'John', + lastName: 'Doe', + email: 'johndoe@gmail.com', + password: 'johnDoe@1', + confirmPassword: 'johnDoe@1', + }; + + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId(/goToRegisterPortion/i)); + + userEvent.type( + screen.getByPlaceholderText(/First Name/i), + formData.firstName, + ); + userEvent.type( + screen.getByPlaceholderText(/Last Name/i), + formData.lastName, + ); + userEvent.type(screen.getByTestId(/signInEmail/i), formData.email); + userEvent.type(screen.getByPlaceholderText('Password'), formData.password); + userEvent.type( + screen.getByPlaceholderText('Confirm Password'), + formData.confirmPassword, + ); + + userEvent.click(screen.getByTestId('registrationBtn')); + + await waitFor(() => { + expect(resetReCAPTCHA).toBeCalled(); + }); + }); + + it('Testing ReCaptcha functionality, it should refresh on unsuccessful login', async () => { + const formData = { + email: 'wrong_email@gmail.com', + password: 'wrong_password', + }; + + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.type(screen.getByTestId(/loginEmail/i), formData.email); + userEvent.type( + screen.getByPlaceholderText(/Enter Password/i), + formData.password, + ); + + userEvent.click(screen.getByTestId('loginBtn')); + + await waitFor(() => { + expect(resetReCAPTCHA).toBeCalled(); + }); + }); + + it('Testing password preview feature for login', async () => { render( @@ -637,7 +739,7 @@ describe('Testing Login Page Screen', () => { await wait(); }); - test('Testing password preview feature for register', async () => { + it('Testing password preview feature for register', async () => { render( @@ -668,7 +770,7 @@ describe('Testing Login Page Screen', () => { await wait(); }); - test('Testing confirm password preview feature', async () => { + it('Testing confirm password preview feature', async () => { render( @@ -699,7 +801,7 @@ describe('Testing Login Page Screen', () => { await wait(); }); - test('Testing for the password error warning when user firsts lands on a page', async () => { + it('Testing for the password error warning when user firsts lands on a page', async () => { render( @@ -716,7 +818,7 @@ describe('Testing Login Page Screen', () => { expect(screen.queryByTestId('passwordCheck')).toBeNull(); }); - test('Testing for the password error warning when user clicks on password field and password is less than 8 character', async () => { + it('Testing for the password error warning when user clicks on password field and password is less than 8 character', async () => { const password = { password: '7', }; @@ -745,7 +847,7 @@ describe('Testing Login Page Screen', () => { expect(screen.queryByTestId('passwordCheck')).toBeInTheDocument(); }); - test('Testing for the password error warning when user clicks on password field and password is greater than or equal to 8 character', async () => { + it('Testing for the password error warning when user clicks on password field and password is greater than or equal to 8 character', async () => { const password = { password: '12345678', }; @@ -774,7 +876,7 @@ describe('Testing Login Page Screen', () => { expect(screen.queryByTestId('passwordCheck')).toBeNull(); }); - test('Testing for the password error warning when user clicks on fields except password field and password is less than 8 character', async () => { + it('Testing for the password error warning when user clicks on fields except password field and password is less than 8 character', async () => { const password = { password: '7', }; @@ -803,7 +905,7 @@ describe('Testing Login Page Screen', () => { expect(screen.queryByTestId('passwordCheck')).toBeInTheDocument(); }); - test('Testing for the password error warning when user clicks on fields except password field and password is greater than or equal to 8 character', async () => { + it('Testing for the password error warning when user clicks on fields except password field and password is greater than or equal to 8 character', async () => { const password = { password: '12345678', }; @@ -834,8 +936,16 @@ describe('Testing Login Page Screen', () => { expect(screen.queryByTestId('passwordCheck')).toBeNull(); }); - test('Component Should be rendered properly for user login', async () => { - window.location.assign('/user/organizations'); + it('Component Should be rendered properly for user login', async () => { + Object.defineProperty(window, 'location', { + configurable: true, + value: { + reload: vi.fn(), + href: 'https://localhost:4321/user/organizations', + origin: 'https://localhost:4321', + pathname: '/user/organizations', + }, + }); render( @@ -854,10 +964,10 @@ describe('Testing Login Page Screen', () => { userEvent.click(userLink); await wait(); expect(screen.getByText(/User Login/i)).toBeInTheDocument(); - expect(window.location).toBeAt('/user/organizations'); + expect(window.location.pathname).toBe('/user/organizations'); }); - test('on value change of ReCAPTCHA onChange event should be triggered in both the captcha', async () => { + it('on value change of ReCAPTCHA onChange event should be triggered in both the captcha', async () => { render( @@ -890,7 +1000,7 @@ describe('Testing Login Page Screen', () => { }); describe('Testing redirect if already logged in', () => { - test('Logged in as USER', async () => { + it('Logged in as USER', async () => { const { setItem } = useLocalStorage(); setItem('IsLoggedIn', 'TRUE'); setItem('userId', 'id'); @@ -908,7 +1018,7 @@ describe('Testing redirect if already logged in', () => { await wait(); expect(mockNavigate).toHaveBeenCalledWith('/user/organizations'); }); - test('Logged in as Admin or SuperAdmin', async () => { + it('Logged in as Admin or SuperAdmin', async () => { const { setItem } = useLocalStorage(); setItem('IsLoggedIn', 'TRUE'); setItem('userId', null); @@ -927,7 +1037,7 @@ describe('Testing redirect if already logged in', () => { expect(mockNavigate).toHaveBeenCalledWith('/orglist'); }); }); -test('Render the Select Organization list and change the option', async () => { +it('Render the Select Organization list and change the option', async () => { render( @@ -951,17 +1061,15 @@ test('Render the Select Organization list and change the option', async () => { fireEvent.change(input, { target: { value: 'a' } }); fireEvent.keyDown(autocomplete, { key: 'ArrowDown' }); fireEvent.keyDown(autocomplete, { key: 'Enter' }); - - debug(); }); describe('Talawa-API server fetch check', () => { beforeEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); }); - test('Checks if Talawa-API resource is loaded successfully', async () => { - global.fetch = jest.fn(() => Promise.resolve({} as unknown as Response)); + it('Checks if Talawa-API resource is loaded successfully', async () => { + global.fetch = vi.fn(() => Promise.resolve({} as unknown as Response)); await act(async () => { render( @@ -980,9 +1088,9 @@ describe('Talawa-API server fetch check', () => { expect(fetch).toHaveBeenCalledWith(BACKEND_URL); }); - test('displays warning message when resource loading fails', async () => { + it('displays warning message when resource loading fails', async () => { const mockError = new Error('Network error'); - global.fetch = jest.fn(() => Promise.reject(mockError)); + global.fetch = vi.fn(() => Promise.reject(mockError)); await act(async () => { render( diff --git a/src/screens/LoginPage/LoginPage.tsx b/src/screens/LoginPage/LoginPage.tsx index 2ed1e71c13..48030d4667 100644 --- a/src/screens/LoginPage/LoginPage.tsx +++ b/src/screens/LoginPage/LoginPage.tsx @@ -1,7 +1,7 @@ import { useQuery, useMutation } from '@apollo/client'; import { Check, Clear } from '@mui/icons-material'; import type { ChangeEvent } from 'react'; -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useRef, useState } from 'react'; import { Form } from 'react-bootstrap'; import Button from 'react-bootstrap/Button'; import Col from 'react-bootstrap/Col'; @@ -30,7 +30,7 @@ import LoginPortalToggle from 'components/LoginPortalToggle/LoginPortalToggle'; import { errorHandler } from 'utils/errorHandler'; import useLocalStorage from 'utils/useLocalstorage'; import { socialMediaLinks } from '../../constants'; -import styles from './LoginPage.module.css'; +import styles from 'style/app.module.css'; import type { InterfaceQueryOrganizationListObject } from 'utils/interfaces'; import { Autocomplete, TextField } from '@mui/material'; import useSession from 'utils/useSession'; @@ -61,6 +61,8 @@ const loginPage = (): JSX.Element => { specialChar: boolean; }; + const loginRecaptchaRef = useRef(null); + const SignupRecaptchaRef = useRef(null); const [recaptchaToken, setRecaptchaToken] = useState(null); const [showTab, setShowTab] = useState<'LOGIN' | 'REGISTER'>('LOGIN'); const [role, setRole] = useState<'admin' | 'user'>('admin'); @@ -153,7 +155,6 @@ const loginPage = (): JSX.Element => { try { await fetch(BACKEND_URL as string); } catch (error) { - /* istanbul ignore next */ errorHandler(t, error); } } @@ -165,7 +166,6 @@ const loginPage = (): JSX.Element => { recaptchaToken: string | null, ): Promise => { try { - /* istanbul ignore next */ if (REACT_APP_USE_RECAPTCHA !== 'yes') { return true; } @@ -176,8 +176,7 @@ const loginPage = (): JSX.Element => { }); return data.recaptcha; - } catch (error) { - /* istanbul ignore next */ + } catch { toast.error(t('captchaError') as string); } }; @@ -199,13 +198,16 @@ const loginPage = (): JSX.Element => { } = signformState; const isVerified = await verifyRecaptcha(recaptchaToken); - /* istanbul ignore next */ + if (!isVerified) { toast.error(t('Please_check_the_captcha') as string); return; } - const isValidatedString = (value: string): boolean => - /^[a-zA-Z]+$/.test(value); + + const isValidName = (value: string): boolean => { + // Allow letters, spaces, and hyphens, but not consecutive spaces or hyphens + return /^[a-zA-Z]+(?:[-\s][a-zA-Z]+)*$/.test(value.trim()); + }; const validatePassword = (password: string): boolean => { const lengthCheck = new RegExp('^.{6,}$'); @@ -219,10 +221,10 @@ const loginPage = (): JSX.Element => { }; if ( - isValidatedString(signfirstName) && - isValidatedString(signlastName) && - signfirstName.length > 1 && - signlastName.length > 1 && + isValidName(signfirstName) && + isValidName(signlastName) && + signfirstName.trim().length > 1 && + signlastName.trim().length > 1 && signEmail.length >= 8 && signPassword.length > 1 && validatePassword(signPassword) @@ -239,7 +241,6 @@ const loginPage = (): JSX.Element => { }, }); - /* istanbul ignore next */ if (signUpData) { toast.success( t( @@ -255,19 +256,20 @@ const loginPage = (): JSX.Element => { cPassword: '', signOrg: '', }); + SignupRecaptchaRef.current?.reset(); } } catch (error) { - /* istanbul ignore next */ errorHandler(t, error); + SignupRecaptchaRef.current?.reset(); } } else { toast.warn(t('passwordMismatches') as string); } } else { - if (!isValidatedString(signfirstName)) { + if (!isValidName(signfirstName)) { toast.warn(t('firstName_invalid') as string); } - if (!isValidatedString(signlastName)) { + if (!isValidName(signlastName)) { toast.warn(t('lastName_invalid') as string); } if (!validatePassword(signPassword)) { @@ -282,7 +284,7 @@ const loginPage = (): JSX.Element => { const loginLink = async (e: ChangeEvent): Promise => { e.preventDefault(); const isVerified = await verifyRecaptcha(recaptchaToken); - /* istanbul ignore next */ + if (!isVerified) { toast.error(t('Please_check_the_captcha') as string); return; @@ -296,7 +298,6 @@ const loginPage = (): JSX.Element => { }, }); - /* istanbul ignore next */ if (loginData) { i18n.changeLanguage(loginData.login.appUserProfile.appLanguageCode); const { login } = loginData; @@ -333,8 +334,8 @@ const loginPage = (): JSX.Element => { toast.warn(tErrors('notFound') as string); } } catch (error) { - /* istanbul ignore next */ errorHandler(t, error); + loginRecaptchaRef.current?.reset(); } }; @@ -441,10 +442,7 @@ const loginPage = (): JSX.Element => { autoComplete="username" data-testid="loginEmail" /> -
@@ -471,7 +469,7 @@ const loginPage = (): JSX.Element => { + + + + + + ); +}; + +export default EditUserTagModal; diff --git a/src/screens/ManageTag/ManageTag.module.css b/src/screens/ManageTag/ManageTag.module.css deleted file mode 100644 index db1886099a..0000000000 --- a/src/screens/ManageTag/ManageTag.module.css +++ /dev/null @@ -1,119 +0,0 @@ -.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.spec.tsx b/src/screens/ManageTag/ManageTag.spec.tsx new file mode 100644 index 0000000000..5d86ed3c17 --- /dev/null +++ b/src/screens/ManageTag/ManageTag.spec.tsx @@ -0,0 +1,506 @@ +import React from 'react'; +import { MockedProvider } from '@apollo/react-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 { 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 } from './ManageTagMocks'; +import { type ApolloLink } from '@apollo/client'; +import { vi, beforeEach, afterEach, expect, it } from 'vitest'; + +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); + +async function wait(ms = 500): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + +vi.mock('react-toastify', () => ({ + toast: { + success: vi.fn(), + info: vi.fn(), + error: vi.fn(), + }, +})); + +/* eslint-disable @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports */ +vi.mock('../../components/AddPeopleToTag/AddPeopleToTag', async () => { + return await import('./ManageTagMockComponents/MockAddPeopleToTag'); +}); + +vi.mock('../../components/TagActions/TagActions', async () => { + return await import('./ManageTagMockComponents/MockTagActions'); +}); +/* eslint-enable @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports */ + +const renderManageTag = (link: ApolloLink): RenderResult => { + return render( + + + + + +
} + /> + } + /> +
} + /> +
} + /> + + + + + , + ); +}; + +describe('Manage Tag Page', () => { + beforeEach(() => { + vi.mock('react-router-dom', async () => ({ + ...(await vi.importActual('react-router-dom')), + })); + }); + + afterEach(() => { + vi.clearAllMocks(); + cleanup(); + }); + + it('Component loads correctly', async () => { + const { getByText } = renderManageTag(link); + + await wait(); + + await waitFor(() => { + expect(getByText(translations.addPeopleToTag)).toBeInTheDocument(); + }); + }); + + it('renders error component on unsuccessful userTag assigned members query', async () => { + const { queryByText } = renderManageTag(link2); + + await wait(); + + await waitFor(() => { + expect(queryByText(translations.addPeopleToTag)).not.toBeInTheDocument(); + }); + }); + + it('opens and closes the add people to tag modal', async () => { + renderManageTag(link); + + await waitFor(() => { + expect(screen.getByTestId('addPeopleToTagBtn')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('addPeopleToTagBtn')); + + await waitFor(() => { + expect(screen.getByTestId('addPeopleToTagModal')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByTestId('closeAddPeopleToTagModal')); + + await waitFor(() => { + expect( + screen.queryByTestId('addPeopleToTagModal'), + ).not.toBeInTheDocument(); + }); + }); + + it('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'), + ); + }); + + it('opens and closes the assignToTags modal', async () => { + renderManageTag(link); + + // Wait for the assignToTags button to be present + await waitFor(() => { + expect(screen.getByTestId('assignToTags')).toBeInTheDocument(); + }); + + // Click the assignToTags button to open the modal + userEvent.click(screen.getByTestId('assignToTags')); + + // Wait for the close button in the modal to be present + await waitFor(() => { + expect(screen.getByTestId('closeTagActionsModalBtn')).toBeInTheDocument(); + }); + + // Click the close button to close the modal + userEvent.click(screen.getByTestId('closeTagActionsModalBtn')); + + // Wait for the modal to be removed from the document + await waitFor(() => { + expect(screen.queryByTestId('tagActionsModal')).not.toBeInTheDocument(); + }); + }); + + it('opens and closes the removeFromTags modal', async () => { + renderManageTag(link); + + // Wait for the removeFromTags button to be present + await waitFor(() => { + expect(screen.getByTestId('removeFromTags')).toBeInTheDocument(); + }); + + // Click the removeFromTags button to open the modal + userEvent.click(screen.getByTestId('removeFromTags')); + + // Wait for the close button in the modal to be present + await waitFor(() => { + expect(screen.getByTestId('closeTagActionsModalBtn')).toBeInTheDocument(); + }); + + // Click the close button to close the modal + userEvent.click(screen.getByTestId('closeTagActionsModalBtn')); + + // Wait for the modal to be removed from the document + await waitFor(() => { + expect(screen.queryByTestId('tagActionsModal')).not.toBeInTheDocument(); + }); + }); + + it('opens and closes the edit tag modal', async () => { + renderManageTag(link); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('editUserTag')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('editUserTag')); + + await waitFor(() => { + return expect( + screen.findByTestId('closeEditTagModalBtn'), + ).resolves.toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('closeEditTagModalBtn')); + + await waitForElementToBeRemoved(() => + screen.queryByTestId('closeEditTagModalBtn'), + ); + }); + + it('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'), + ); + }); + + it("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(); + }); + }); + + it('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(); + }); + }); + + it('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(); + }); + }); + + it('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(); + }); + }); + + it('searchs for tags where the name matches the provided search input', async () => { + renderManageTag(link); + + await wait(); + + await waitFor(() => { + expect( + screen.getByPlaceholderText(translations.searchByName), + ).toBeInTheDocument(); + }); + const input = screen.getByPlaceholderText(translations.searchByName); + fireEvent.change(input, { target: { value: 'assigned user' } }); + + // should render the two users from the mock data + // where firstName starts with "assigned" and lastName starts with "user" + await waitFor(() => { + const buttons = screen.getAllByTestId('viewProfileBtn'); + expect(buttons.length).toEqual(2); + }); + }); + + it('fetches the tags by the sort order, i.e. latest or oldest first', async () => { + renderManageTag(link); + + await wait(); + + await waitFor(() => { + expect( + screen.getByPlaceholderText(translations.searchByName), + ).toBeInTheDocument(); + }); + const input = screen.getByPlaceholderText(translations.searchByName); + fireEvent.change(input, { target: { value: 'assigned user' } }); + + // should render the two searched tags from the mock data + // where name starts with "searchUserTag" + await waitFor(() => { + expect(screen.getAllByTestId('memberName')[0]).toHaveTextContent( + 'assigned user1', + ); + }); + + // now change the sorting order + await waitFor(() => { + expect(screen.getByTestId('sortPeople')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('sortPeople')); + + await waitFor(() => { + expect(screen.getByTestId('oldest')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('oldest')); + + // returns the tags in reverse order + await waitFor(() => { + expect(screen.getAllByTestId('memberName')[0]).toHaveTextContent( + 'assigned user2', + ); + }); + + await waitFor(() => { + expect(screen.getByTestId('sortPeople')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('sortPeople')); + + await waitFor(() => { + expect(screen.getByTestId('latest')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('latest')); + + // reverse the order again + await waitFor(() => { + expect(screen.getAllByTestId('memberName')[0]).toHaveTextContent( + 'assigned user1', + ); + }); + }); + + it('Fetches more assigned members with infinite scroll', async () => { + const { getByText } = renderManageTag(link); + + await wait(); + + await waitFor(() => { + expect(getByText(translations.addPeopleToTag)).toBeInTheDocument(); + }); + + const manageTagScrollableDiv = screen.getByTestId('manageTagScrollableDiv'); + + // Get the initial number of tags loaded + const initialAssignedMembersDataLength = + screen.getAllByTestId('viewProfileBtn').length; + + // Set scroll position to the bottom + fireEvent.scroll(manageTagScrollableDiv, { + target: { scrollY: manageTagScrollableDiv.scrollHeight }, + }); + + await waitFor(() => { + const finalAssignedMembersDataLength = + screen.getAllByTestId('viewProfileBtn').length; + expect(finalAssignedMembersDataLength).toBeGreaterThan( + initialAssignedMembersDataLength, + ); + + expect(getByText(translations.addPeopleToTag)).toBeInTheDocument(); + }); + }); + + it('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, + ); + }); + }); + + it('successfully edits the tag name', async () => { + renderManageTag(link); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('editUserTag')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('editUserTag')); + + 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, + ); + }); + }); + + it('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.test.tsx b/src/screens/ManageTag/ManageTag.test.tsx deleted file mode 100644 index 38ebba7402..0000000000 --- a/src/screens/ManageTag/ManageTag.test.tsx +++ /dev/null @@ -1,296 +0,0 @@ -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(), - error: jest.fn(), - }, -})); - -const cache = new InMemoryCache({ - typePolicies: { - Query: { - fields: { - getUserTag: { - keyArgs: false, - merge(existing = {}, incoming) { - return incoming; - }, - }, - }, - }, - }, -}); - -const renderManageTag = (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 } = 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("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).toBeCalledWith(translations.successfullyUnassigned); - }); - }); -}); diff --git a/src/screens/ManageTag/ManageTag.tsx b/src/screens/ManageTag/ManageTag.tsx index 86a44fb169..7eb6a3221d 100644 --- a/src/screens/ManageTag/ManageTag.tsx +++ b/src/screens/ManageTag/ManageTag.tsx @@ -1,5 +1,6 @@ -import React, { useState } from 'react'; -import { useMutation, useQuery, type ApolloError } from '@apollo/client'; +import type { FormEvent } from 'react'; +import React, { useEffect, useState } from 'react'; +import { useMutation, useQuery } from '@apollo/client'; import { Search, WarningAmberRounded } from '@mui/icons-material'; import SortIcon from '@mui/icons-material/Sort'; import Loader from 'components/Loader/Loader'; @@ -8,27 +9,39 @@ 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 styles from '../../style/app.module.css'; import { DataGrid } from '@mui/x-data-grid'; -import { dataGridStyle } from 'utils/organizationTagsUtils'; +import type { + InterfaceTagAssignedMembersQuery, + SortedByType, + TagActionType, +} from 'utils/organizationTagsUtils'; +import { + TAGS_QUERY_DATA_CHUNK_SIZE, + dataGridStyle, +} from 'utils/organizationTagsUtils'; import type { GridCellParams, GridColDef } from '@mui/x-data-grid'; import { Stack } from '@mui/material'; -import { UNASSIGN_USER_TAG } from 'GraphQl/Mutations/TagMutations'; import { - USER_TAG_ANCESTORS, - USER_TAGS_ASSIGNED_MEMBERS, -} from 'GraphQl/Queries/userTagQueries'; + REMOVE_USER_TAG, + UNASSIGN_USER_TAG, + UPDATE_USER_TAG, +} from 'GraphQl/Mutations/TagMutations'; +import { USER_TAGS_ASSIGNED_MEMBERS } from 'GraphQl/Queries/userTagQueries'; +import AddPeopleToTag from 'components/AddPeopleToTag/AddPeopleToTag'; +import TagActions from 'components/TagActions/TagActions'; +import InfiniteScroll from 'react-infinite-scroll-component'; +import InfiniteScrollLoader from 'components/InfiniteScrollLoader/InfiniteScrollLoader'; +import EditUserTagModal from './EditUserTagModal'; +import RemoveUserTagModal from './RemoveUserTagModal'; +import UnassignUserTagModal from './UnassignUserTagModal'; /** - * 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. + * Component that renders the Manage Tag screen when the app navigates to '/orgtags/:orgId/manageTag/:tagId'. */ function ManageTag(): JSX.Element { @@ -36,73 +49,120 @@ function ManageTag(): JSX.Element { keyPrefix: 'manageTag', }); const { t: tCommon } = useTranslation('common'); - - const [addPeopleToTagModalIsOpen, setAddPeopleToTagModalIsOpen] = - useState(false); - const [unassignTagModalIsOpen, setUnassignTagModalIsOpen] = 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 [unassignUserTagModalIsOpen, setUnassignUserTagModalIsOpen] = + useState(false); + const [addPeopleToTagModalIsOpen, setAddPeopleToTagModalIsOpen] = + useState(false); + const [tagActionsModalIsOpen, setTagActionsModalIsOpen] = useState(false); + const [editUserTagModalIsOpen, setEditUserTagModalIsOpen] = useState(false); + const [removeUserTagModalIsOpen, setRemoveUserTagModalIsOpen] = + useState(false); const [unassignUserId, setUnassignUserId] = useState(null); - + const [assignedMemberSearchInput, setAssignedMemberSearchInput] = + useState(''); + const [assignedMemberSearchFirstName, setAssignedMemberSearchFirstName] = + useState(''); + const [assignedMemberSearchLastName, setAssignedMemberSearchLastName] = + useState(''); + const [assignedMemberSortOrder, setAssignedMemberSortOrder] = + useState('DESCENDING'); + // a state to specify whether we're assigning to tags or removing from tags + const [tagActionType, setTagActionType] = + useState('assignToTags'); + + const toggleRemoveUserTagModal = (): void => { + setRemoveUserTagModalIsOpen(!removeUserTagModalIsOpen); + }; const showAddPeopleToTagModal = (): void => { setAddPeopleToTagModalIsOpen(true); }; - const hideAddPeopleToTagModal = (): void => { setAddPeopleToTagModalIsOpen(false); }; + const showTagActionsModal = (): void => { + setTagActionsModalIsOpen(true); + }; + const hideTagActionsModal = (): void => { + setTagActionsModalIsOpen(false); + }; + const showEditUserTagModal = (): void => { + setEditUserTagModalIsOpen(true); + }; + const hideEditUserTagModal = (): void => { + setEditUserTagModalIsOpen(false); + }; const { data: userTagAssignedMembersData, loading: userTagAssignedMembersLoading, error: userTagAssignedMembersError, refetch: userTagAssignedMembersRefetch, - }: { - data?: { - getUserTag: InterfaceQueryUserTagsAssignedMembers; - }; - loading: boolean; - error?: ApolloError; - refetch: () => void; - } = useQuery(USER_TAGS_ASSIGNED_MEMBERS, { + fetchMore: fetchMoreAssignedMembers, + }: InterfaceTagAssignedMembersQuery = useQuery(USER_TAGS_ASSIGNED_MEMBERS, { variables: { id: currentTagId, - after: after, - before: before, - first: first, - last: last, + first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { + firstName: { starts_with: assignedMemberSearchFirstName }, + lastName: { starts_with: assignedMemberSearchLastName }, + }, + sortedBy: { id: assignedMemberSortOrder }, }, + fetchPolicy: 'no-cache', }); - 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: currentTagId, - }, - }); + const loadMoreAssignedMembers = (): void => { + fetchMoreAssignedMembers({ + variables: { + first: TAGS_QUERY_DATA_CHUNK_SIZE, + after: + userTagAssignedMembersData?.getAssignedUsers.usersAssignedTo.pageInfo + .endCursor, + }, + updateQuery: ( + prevResult: { getAssignedUsers: InterfaceQueryUserTagsAssignedMembers }, + { + fetchMoreResult, + }: { + fetchMoreResult: { + getAssignedUsers: InterfaceQueryUserTagsAssignedMembers; + }; + }, + ) => { + /* istanbul ignore next -- @preserve */ + if (!fetchMoreResult) return prevResult; + + return { + getAssignedUsers: { + ...fetchMoreResult.getAssignedUsers, + usersAssignedTo: { + ...fetchMoreResult.getAssignedUsers.usersAssignedTo, + edges: [ + ...prevResult.getAssignedUsers.usersAssignedTo.edges, + ...fetchMoreResult.getAssignedUsers.usersAssignedTo.edges, + ], + }, + }, + }; + }, + }); + }; + + useEffect(() => { + const [firstName, ...lastNameParts] = assignedMemberSearchInput + .trim() + .split(/\s+/); + const lastName = lastNameParts.join(' '); // Joins everything after the first word + setAssignedMemberSearchFirstName(firstName); + setAssignedMemberSearchLastName(lastName); + }, [assignedMemberSearchInput]); const [unassignUserTag] = useMutation(UNASSIGN_USER_TAG); - const handleUnassignTag = async (): Promise => { + const handleUnassignUserTag = async (): Promise => { try { await unassignUserTag({ variables: { @@ -112,32 +172,85 @@ function ManageTag(): JSX.Element { }); userTagAssignedMembersRefetch(); - toggleUnassignTagModal(); + toggleUnassignUserTagModal(); toast.success(t('successfullyUnassigned') as string); } catch (error: unknown) { - /* istanbul ignore next */ + /* istanbul ignore next -- @preserve */ if (error instanceof Error) { toast.error(error.message); } } }; - if (userTagAssignedMembersLoading || orgUserTagsAncestorsLoading) { - return ; - } + const [edit] = useMutation(UPDATE_USER_TAG); + + const [newTagName, setNewTagName] = useState(''); + const currentTagName = + userTagAssignedMembersData?.getAssignedUsers.name ?? ''; + + useEffect(() => { + setNewTagName(userTagAssignedMembersData?.getAssignedUsers.name ?? ''); + }, [userTagAssignedMembersData]); + + const handleEditUserTag = async ( + e: FormEvent, + ): Promise => { + e.preventDefault(); + + if (newTagName === currentTagName) { + toast.info(t('changeNameToEdit')); + return; + } + + try { + const { data } = await edit({ + variables: { + tagId: currentTagId, + name: newTagName, + }, + }); + + /* istanbul ignore else -- @preserve */ + if (data) { + toast.success(t('tagUpdationSuccess')); + userTagAssignedMembersRefetch(); + setEditUserTagModalIsOpen(false); + } + } catch (error: unknown) { + /* istanbul ignore next -- @preserve */ + 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 -- @preserve */ + if (error instanceof Error) { + toast.error(error.message); + } + } + }; - if (userTagAssignedMembersError || orgUserTagsAncestorsError) { + if (userTagAssignedMembersError) { return (
- Error occured while loading{' '} - {userTagAssignedMembersError ? 'assigned users' : 'tag ancestors'} -
- {userTagAssignedMembersError - ? userTagAssignedMembersError.message - : orgUserTagsAncestorsError?.message} + Error occured while loading assigned users
@@ -145,43 +258,31 @@ function ManageTag(): JSX.Element { } const userTagAssignedMembers = - userTagAssignedMembersData?.getUserTag.usersAssignedTo.edges.map( + userTagAssignedMembersData?.getAssignedUsers.usersAssignedTo.edges.map( (edge) => edge.node, - ); + ) ?? /* istanbul ignore next -- @preserve */ []; - const orgUserTagAncestors = orgUserTagAncestorsData?.getUserTagAncestors; + // get the ancestorTags array and push the current tag in it + // used for the tag breadcrumbs + const orgUserTagAncestors = [ + ...(userTagAssignedMembersData?.getAssignedUsers.ancestorTags ?? []), + { + _id: currentTagId, + name: currentTagName, + }, + ]; const redirectToSubTags = (tagId: string): void => { navigate(`/orgtags/${orgId}/subTags/${tagId}`); }; - const redirectToManageTag = (tagId: string): void => { - navigate(`/orgtags/${orgId}/managetag/${tagId}`); + 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) { + const toggleUnassignUserTagModal = (): void => { + if (unassignUserTagModalIsOpen) { setUnassignUserId(null); } - setUnassignTagModalIsOpen(!unassignTagModalIsOpen); + setUnassignUserTagModalIsOpen(!unassignUserTagModalIsOpen); }; const columns: GridColDef[] = [ @@ -191,7 +292,7 @@ function ManageTag(): JSX.Element { minWidth: 100, align: 'center', headerAlign: 'center', - headerClassName: `${styles.tableHeader}`, + headerClassName: `${styles.tableHeaders}`, sortable: false, renderCell: (params: GridCellParams) => { return
{params.row.id}
; @@ -203,7 +304,7 @@ function ManageTag(): JSX.Element { flex: 2, minWidth: 100, sortable: false, - headerClassName: `${styles.tableHeader}`, + headerClassName: `${styles.tableHeaders}`, renderCell: (params: GridCellParams) => { return (
@@ -220,26 +321,26 @@ function ManageTag(): JSX.Element { minWidth: 100, headerAlign: 'center', sortable: false, - headerClassName: `${styles.tableHeader}`, + headerClassName: `${styles.tableHeaders}`, renderCell: (params: GridCellParams) => { return ( -
+
-
{t('viewProfile')}
+
+ {t('viewProfile')} +
-
- - -
+
- - -
-
- -
- -
navigate(`/orgtags/${orgId}`)} - className={`fs-6 ms-3 my-1 ${styles.tagsBreadCrumbs}`} - data-testid="allTagsBtn" - > - {'Tags'} - -
- - {orgUserTagAncestors?.map((tag, index) => ( + {userTagAssignedMembersLoading ? ( + + ) : ( + + +
+
+ +
redirectToManageTag(tag._id as string)} - data-testid="redirectToManageTag" + onClick={() => navigate(`/orgtags/${orgId}`)} + className={`fs-6 ms-3 my-1 ${styles.tagsBreadCrumbs}`} + data-testid="allTagsBtn" > - {tag.name} - - {orgUserTagAncestors.length - 1 !== index && ( - /* istanbul ignore next */ - - )} + {'Tags'} +
- ))} -
- row._id} - slots={{ - noRowsOverlay: /* istanbul ignore next */ () => ( - ( +
redirectToManageTag(tag._id as string)} + data-testid="redirectToManageTag" > - {t('noAssignedMembersFound')} - - ), - }} - sx={dataGridStyle} - getRowClassName={() => `${styles.rowBackground}`} - autoHeight - rowHeight={65} - rows={userTagAssignedMembers?.map((assignedMembers, index) => ({ - id: index + 1, - ...assignedMembers, - }))} - columns={columns} - isRowSelectable={() => false} - /> - -
-
- + {tag.name} + {orgUserTagAncestors.length - 1 !== index && ( + /* istanbul ignore next -- @preserve */ + + )} +
+ ))}
-
- -
-
- - - -
-
{'Actions'}
-
-
-
- {'Email Users'} + row.id} + slots={{ + noRowsOverlay: + /* istanbul ignore next -- @preserve */ () => ( + + {t('noAssignedMembersFound')} + + ), + }} + sx={dataGridStyle} + getRowClassName={() => `${styles.rowBackgrounds}`} + autoHeight + rowHeight={65} + rows={userTagAssignedMembers?.map( + (assignedMembers, index) => ({ + id: index + 1, + ...assignedMembers, + }), + )} + columns={columns} + isRowSelectable={() => false} + /> +
-
-
-
-
- {'Add to tags'} + + +
+
{'Actions'}
-
- {'Remove from tags'} +
+
{ + setTagActionType('assignToTags'); + showTagActionsModal(); + }} + className="my-2 btn btn-primary btn-sm w-75" + data-testid="assignToTags" + > + {t('assignToTags')} +
+
{ + setTagActionType('removeFromTags'); + showTagActionsModal(); + }} + className="mb-1 btn btn-danger btn-sm w-75" + data-testid="removeFromTags" + > + {t('removeFromTags')} +
+
+
+ {tCommon('edit')} +
+
+ {tCommon('remove')} +
-
- - + + + )}
{/* Add People To Tag Modal */} - - - {t('addPeople')} - -
- - - - - - -
-
- - {/* Unassign Tag Modal */} - - - - {t('unassignUserTag')} - - - {t('unassignUserTagMessage')} - - - - - + + {/* Assign People To Tags Modal */} + + {/* Unassign User Tag Modal */} + + {/* Edit User Tag Modal */} + + {/* Remove User Tag Modal */} + ); } - export default ManageTag; diff --git a/src/screens/ManageTag/ManageTagMockComponents/MockAddPeopleToTag.tsx b/src/screens/ManageTag/ManageTagMockComponents/MockAddPeopleToTag.tsx new file mode 100644 index 0000000000..7e62c47f86 --- /dev/null +++ b/src/screens/ManageTag/ManageTagMockComponents/MockAddPeopleToTag.tsx @@ -0,0 +1,42 @@ +import React from 'react'; +import type { InterfaceAddPeopleToTagProps } from '../../../components/AddPeopleToTag/AddPeopleToTag'; + +/** + * Component that mocks the AddPeopleToTag component for the Manage Tag screen. + */ + +const TEST_IDS = { + MODAL: 'addPeopleToTagModal', + CLOSE_BUTTON: 'closeAddPeopleToTagModal', +} as const; +const MockAddPeopleToTag: React.FC = ({ + addPeopleToTagModalIsOpen, + hideAddPeopleToTagModal, +}) => { + return ( + <> + {addPeopleToTagModalIsOpen && ( +
+ + +
+ )} + + ); +}; + +export default MockAddPeopleToTag; diff --git a/src/screens/ManageTag/ManageTagMockComponents/MockTagActions.tsx b/src/screens/ManageTag/ManageTagMockComponents/MockTagActions.tsx new file mode 100644 index 0000000000..3d2d6cc880 --- /dev/null +++ b/src/screens/ManageTag/ManageTagMockComponents/MockTagActions.tsx @@ -0,0 +1,37 @@ +import React from 'react'; +import type { InterfaceTagActionsProps } from '../../../components/TagActions/TagActions'; + +/** + * Component that mocks the TagActions component for the Manage Tag screen. + */ + +const MockTagActions: React.FC = ({ + tagActionsModalIsOpen, + hideTagActionsModal, +}) => { + return ( + <> + {tagActionsModalIsOpen && ( +
+

+ Tag Actions +

+ +
+ )} + + ); +}; + +export default MockTagActions; diff --git a/src/screens/ManageTag/ManageTagMocks.ts b/src/screens/ManageTag/ManageTagMocks.ts index c42c4a9e5f..5ce1e62595 100644 --- a/src/screens/ManageTag/ManageTagMocks.ts +++ b/src/screens/ManageTag/ManageTagMocks.ts @@ -1,8 +1,10 @@ -import { UNASSIGN_USER_TAG } from 'GraphQl/Mutations/TagMutations'; import { - USER_TAG_ANCESTORS, - USER_TAGS_ASSIGNED_MEMBERS, -} from 'GraphQl/Queries/userTagQueries'; + REMOVE_USER_TAG, + UNASSIGN_USER_TAG, + UPDATE_USER_TAG, +} from 'GraphQl/Mutations/TagMutations'; +import { USER_TAGS_ASSIGNED_MEMBERS } from 'GraphQl/Queries/userTagQueries'; +import { TAGS_QUERY_DATA_CHUNK_SIZE } from 'utils/organizationTagsUtils'; export const MOCKS = [ { @@ -10,15 +12,17 @@ export const MOCKS = [ query: USER_TAGS_ASSIGNED_MEMBERS, variables: { id: '1', - after: null, - before: null, - first: 5, - last: null, + first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { + firstName: { starts_with: '' }, + lastName: { starts_with: '' }, + }, + sortedBy: { id: 'DESCENDING' }, }, }, result: { data: { - getUserTag: { + getAssignedUsers: { name: 'tag1', usersAssignedTo: { edges: [ @@ -62,15 +66,56 @@ export const MOCKS = [ }, cursor: '5', }, + { + node: { + _id: '6', + firstName: 'member', + lastName: '6', + }, + cursor: '6', + }, + { + node: { + _id: '7', + firstName: 'member', + lastName: '7', + }, + cursor: '7', + }, + { + 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: '1', - endCursor: '5', + endCursor: '10', hasNextPage: true, hasPreviousPage: false, }, - totalCount: 6, + totalCount: 12, }, + ancestorTags: [], }, }, }, @@ -80,35 +125,47 @@ export const MOCKS = [ query: USER_TAGS_ASSIGNED_MEMBERS, variables: { id: '1', - after: '5', - before: null, - first: 5, - last: null, + first: TAGS_QUERY_DATA_CHUNK_SIZE, + after: '10', + where: { + firstName: { starts_with: '' }, + lastName: { starts_with: '' }, + }, + sortedBy: { id: 'DESCENDING' }, }, }, result: { data: { - getUserTag: { + getAssignedUsers: { name: 'tag1', usersAssignedTo: { edges: [ { node: { - _id: '6', + _id: '11', firstName: 'member', - lastName: '6', + lastName: '11', }, - cursor: '6', + cursor: '11', + }, + { + node: { + _id: '12', + firstName: 'member', + lastName: '12', + }, + cursor: '12', }, ], pageInfo: { - startCursor: '6', - endCursor: '6', + startCursor: '11', + endCursor: '12', hasNextPage: false, hasPreviousPage: true, }, - totalCount: 6, + totalCount: 12, }, + ancestorTags: [], }, }, }, @@ -118,86 +175,96 @@ export const MOCKS = [ query: USER_TAGS_ASSIGNED_MEMBERS, variables: { id: '1', - after: null, - before: '6', - first: null, - last: 5, + first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { + firstName: { starts_with: 'assigned' }, + lastName: { starts_with: 'user' }, + }, + sortedBy: { id: 'DESCENDING' }, }, }, result: { data: { - getUserTag: { + getAssignedUsers: { name: 'tag1', usersAssignedTo: { edges: [ { node: { _id: '1', - firstName: 'member', - lastName: '1', + firstName: 'assigned', + lastName: 'user1', }, cursor: '1', }, { node: { _id: '2', - firstName: 'member', - lastName: '2', + firstName: 'assigned', + lastName: 'user2', }, 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, + endCursor: '2', + hasNextPage: false, hasPreviousPage: false, }, - totalCount: 6, + totalCount: 2, }, + ancestorTags: [], }, }, }, }, { request: { - query: USER_TAG_ANCESTORS, + query: USER_TAGS_ASSIGNED_MEMBERS, variables: { id: '1', + first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { + firstName: { starts_with: 'assigned' }, + lastName: { starts_with: 'user' }, + }, + sortedBy: { id: 'ASCENDING' }, }, }, result: { data: { - getUserTagAncestors: [ - { - _id: '1', - name: 'tag1', + getAssignedUsers: { + name: 'tag1', + usersAssignedTo: { + edges: [ + { + node: { + _id: '2', + firstName: 'assigned', + lastName: 'user2', + }, + cursor: '2', + }, + { + node: { + _id: '1', + firstName: 'assigned', + lastName: 'user1', + }, + cursor: '1', + }, + ], + pageInfo: { + startCursor: '2', + endCursor: '1', + hasNextPage: false, + hasPreviousPage: false, + }, + totalCount: 2, }, - ], + ancestorTags: [], + }, }, }, }, @@ -217,72 +284,51 @@ export const MOCKS = [ }, }, }, -]; - -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, + query: UPDATE_USER_TAG, variables: { - id: '1', + tagId: '1', + name: 'tag 1 edited', }, }, result: { data: { - getUserTagAncestors: [], + updateUserTag: { + _id: '1', + }, }, }, }, -]; - -export const MOCKS_ERROR_TAG_ANCESTORS = [ { request: { - query: USER_TAGS_ASSIGNED_MEMBERS, + query: REMOVE_USER_TAG, 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, - }, + removeUserTag: { + _id: '1', }, }, }, }, +]; + +export const MOCKS_ERROR_ASSIGNED_MEMBERS = [ { request: { - query: USER_TAG_ANCESTORS, + query: USER_TAGS_ASSIGNED_MEMBERS, variables: { id: '1', + first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { + firstName: { starts_with: '' }, + lastName: { starts_with: '' }, + }, + sortedBy: { id: 'DESCENDING' }, }, }, error: new Error('Mock Graphql Error'), diff --git a/src/screens/ManageTag/RemoveUserTagModal.tsx b/src/screens/ManageTag/RemoveUserTagModal.tsx new file mode 100644 index 0000000000..dc000f443c --- /dev/null +++ b/src/screens/ManageTag/RemoveUserTagModal.tsx @@ -0,0 +1,72 @@ +import type { TFunction } from 'i18next'; +import React from 'react'; +import { Button, Modal } from 'react-bootstrap'; + +/** + * Remove UserTag Modal component for the Manage Tag screen. + */ + +export interface InterfaceRemoveUserTagModalProps { + removeUserTagModalIsOpen: boolean; + toggleRemoveUserTagModal: () => void; + handleRemoveUserTag: () => Promise; + t: TFunction<'translation', 'manageTag'>; + tCommon: TFunction<'common', undefined>; +} + +const RemoveUserTagModal: React.FC = ({ + removeUserTagModalIsOpen, + toggleRemoveUserTagModal, + handleRemoveUserTag, + t, + tCommon, +}) => { + return ( + <> + + + + {t('removeUserTag')} + + + + {t('removeUserTagMessage')} + + + + + + + + ); +}; + +export default RemoveUserTagModal; diff --git a/src/screens/ManageTag/UnassignUserTagModal.tsx b/src/screens/ManageTag/UnassignUserTagModal.tsx new file mode 100644 index 0000000000..9d926790c3 --- /dev/null +++ b/src/screens/ManageTag/UnassignUserTagModal.tsx @@ -0,0 +1,80 @@ +import type { TFunction } from 'i18next'; +import React from 'react'; +import { Button, Modal } from 'react-bootstrap'; + +/** + * Unassign UserTag Modal component for the Manage Tag screen. + */ + +export interface InterfaceUnassignUserTagModalProps { + unassignUserTagModalIsOpen: boolean; + toggleUnassignUserTagModal: () => void; + handleUnassignUserTag: () => Promise; + t: TFunction<'translation', 'manageTag' | 'memberDetail'>; + tCommon: TFunction<'common', undefined>; +} + +const UnassignUserTagModal: React.FC = ({ + unassignUserTagModalIsOpen, + toggleUnassignUserTagModal, + handleUnassignUserTag, + t, + tCommon, +}) => { + return ( + <> + + + + {t('unassignUserTag')} + + + {t('unassignUserTagMessage')} + + + + + + + ); +}; + +export default UnassignUserTagModal; diff --git a/src/screens/MemberDetail/MemberDetail.module.css b/src/screens/MemberDetail/MemberDetail.module.css index 603e55d1d9..7b421adcf8 100644 --- a/src/screens/MemberDetail/MemberDetail.module.css +++ b/src/screens/MemberDetail/MemberDetail.module.css @@ -10,6 +10,30 @@ height: 100%; } +.editIcon { + position: absolute; + top: 10px; + left: 20px; + cursor: pointer; +} +.selectWrapper { + position: relative; +} + +.selectWithChevron { + appearance: none; + padding-right: 30px; +} + +.selectWrapper::after { + content: '\25BC'; + position: absolute; + top: 50%; + right: 10px; + transform: translateY(-50%); + pointer-events: none; +} + .sidebar:after { content: ''; background-color: #f7f7f7; @@ -55,6 +79,10 @@ width: 60%; } +.contact { + width: 100%; +} + .sidebarsticky > input { text-decoration: none; margin-bottom: 50px; @@ -88,6 +116,10 @@ border-bottom: 3px solid #31bb6b; width: 60%; } +.cardBody { + height: 35vh; + overflow-y: scroll; +} .admindetails { display: flex; @@ -238,7 +270,6 @@ padding: 10px 10px; border-radius: 5px; background-color: #31bb6b; - width: 100%; font-size: 16px; color: white; outline: none; @@ -247,7 +278,23 @@ transition: transform 0.2s, box-shadow 0.2s; - width: 100%; +} +.whiteregbtn { + margin: 1rem 0 0; + margin-right: 2px; + margin-top: 10px; + border: 1px solid #31bb6b; + padding: 10px 10px; + border-radius: 5px; + background-color: white; + font-size: 16px; + color: #31bb6b; + outline: none; + font-weight: 600; + cursor: pointer; + transition: + transform 0.2s, + box-shadow 0.2s; } .loader, @@ -453,11 +500,112 @@ border-top-left-radius: 16px; border-top-right-radius: 16px; } +.eventContainer { + display: flex; + align-items: start; +} + +.eventDetailsBox { + position: relative; + box-sizing: border-box; + background: #ffffff; + width: 66%; + box-shadow: 0 3px 8px rgba(0, 0, 0, 0.1); + border-radius: 20px; + margin-bottom: 0; + margin-top: 20px; +} +.ctacards { + padding: 20px; + width: 100%; + display: flex; + margin: 0 4px; + justify-content: space-between; + box-shadow: 0 3px 8px rgba(0, 0, 0, 0.1); + align-items: center; + border-radius: 20px; +} +.ctacards span { + color: rgb(181, 181, 181); + font-size: small; +} +/* .eventDetailsBox::before { + content: ''; + position: absolute; + top: 0; + height: 100%; + width: 6px; + background-color: #31bb6b; + border-radius: 20px; +} */ + +.time { + display: flex; + justify-content: space-between; + padding: 15px; + padding-bottom: 0px; + width: 33%; + + box-sizing: border-box; + background: #ffffff; + box-shadow: 0 3px 8px rgba(0, 0, 0, 0.1); + border-radius: 20px; + margin-bottom: 0; + margin-top: 20px; + margin-left: 10px; +} + +.startTime, +.endTime { + display: flex; + font-size: 20px; +} + +.to { + padding-right: 10px; +} + +.startDate, +.endDate { + color: #808080; + font-size: 14px; +} + +.titlename { + font-weight: 600; + font-size: 25px; + padding: 15px; + padding-bottom: 0px; + width: 50%; +} + +.description { + color: #737373; + font-weight: 300; + font-size: 14px; + word-wrap: break-word; + padding: 15px; + padding-bottom: 0px; +} + +.toporgloc { + font-size: 16px; + padding: 15px; + padding-bottom: 0px; +} + +.toporgloc span { + color: #737373; +} .inputColor { background: #f1f3f6; } - +.cardHeader { + display: flex; + justify-content: space-between; + align-items: center; +} .width60 { width: 60%; } @@ -465,6 +613,9 @@ .maxWidth40 { max-width: 40%; } +.maxWidth50 { + max-width: 50%; +} .allRound { border-radius: 16px; @@ -521,3 +672,15 @@ input::file-selector-button { .Outline { outline: 1px solid var(--bs-gray-400); } + +.tagLink { + font-weight: 600; + color: var(--bs-gray-700); + cursor: pointer; +} + +.tagLink:hover { + font-weight: 800; + color: var(--bs-blue); + text-decoration: underline; +} diff --git a/src/screens/MemberDetail/MemberDetail.spec.tsx b/src/screens/MemberDetail/MemberDetail.spec.tsx new file mode 100644 index 0000000000..4c1a68369f --- /dev/null +++ b/src/screens/MemberDetail/MemberDetail.spec.tsx @@ -0,0 +1,408 @@ +import React from 'react'; +import type { RenderResult } from '@testing-library/react'; +import { + act, + cleanup, + fireEvent, + render, + screen, + waitFor, + waitForElementToBeRemoved, +} from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import userEvent from '@testing-library/user-event'; +import { BrowserRouter, MemoryRouter, Route, Routes } 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 { StaticMockLink } from 'utils/StaticMockLink'; +import MemberDetail, { getLanguageName, prettyDate } from './MemberDetail'; +import { MOCKS1, MOCKS2, MOCKS3 } from './MemberDetailMocks'; +import type { ApolloLink } from '@apollo/client'; +import { toast } from 'react-toastify'; +import { vi } from 'vitest'; + +const link1 = new StaticMockLink(MOCKS1, true); +const link2 = new StaticMockLink(MOCKS2, true); +const link3 = new StaticMockLink(MOCKS3, true); + +async function wait(ms = 500): Promise { + await act(() => new Promise((resolve) => setTimeout(resolve, ms))); +} + +const translations = { + ...JSON.parse( + JSON.stringify( + i18nForTest.getDataByLanguage('en')?.translation.memberDetail ?? {}, + ), + ), + ...JSON.parse( + JSON.stringify(i18nForTest.getDataByLanguage('en')?.common ?? {}), + ), + ...JSON.parse( + JSON.stringify(i18nForTest.getDataByLanguage('en')?.errors ?? {}), + ), +}; + +vi.mock('@mui/x-date-pickers/DateTimePicker', async () => { + const actual = await vi.importActual( + '@mui/x-date-pickers/DesktopDateTimePicker', + ); + return { + DateTimePicker: actual.DesktopDateTimePicker, + }; +}); + +vi.mock('react-toastify', () => ({ + toast: { + success: vi.fn(), + error: vi.fn(), + }, +})); + +vi.mock('@dicebear/core', () => ({ + createAvatar: vi.fn(() => ({ + toDataUri: vi.fn(() => 'mocked-data-uri'), + })), +})); + +const props = { + id: 'rishav-jha-mech', +}; + +const renderMemberDetailScreen = (link: ApolloLink): RenderResult => { + return render( + + + + + + } + /> +
} + /> + + + + + , + ); +}; + +describe('MemberDetail', () => { + global.alert = vi.fn(); + + afterEach(() => { + vi.clearAllMocks(); + cleanup(); + }); + + test('should render the elements', async () => { + renderMemberDetailScreen(link1); + + await wait(); + + expect(screen.queryByText('Loading data...')).not.toBeInTheDocument(); + expect(screen.getAllByText(/Email/i)).toBeTruthy(); + expect(screen.getAllByText(/First name/i)).toBeTruthy(); + expect(screen.getAllByText(/Last name/i)).toBeTruthy(); + // expect(screen.getAllByText(/Language/i)).toBeTruthy(); + // expect(screen.getByText(/Plugin creation allowed/i)).toBeInTheDocument(); + // expect(screen.getAllByText(/Joined on/i)).toBeTruthy(); + // expect(screen.getAllByText(/Joined On/i)).toHaveLength(1); + expect(screen.getAllByText(/Profile Details/i)).toHaveLength(1); + // expect(screen.getAllByText(/Actions/i)).toHaveLength(1); + expect(screen.getAllByText(/Contact Information/i)).toHaveLength(1); + expect(screen.getAllByText(/Events Attended/i)).toHaveLength(2); + }); + + test('prettyDate function should work properly', () => { + // If the date is provided + const datePretty = vi.fn(prettyDate); + expect(datePretty('2023-02-18T09:22:27.969Z')).toBe( + prettyDate('2023-02-18T09:22:27.969Z'), + ); + // If there's some error in formatting the date + expect(datePretty('')).toBe('Unavailable'); + }); + + test('getLanguageName function should work properly', () => { + const getLangName = vi.fn(getLanguageName); + // If the language code is provided + expect(getLangName('en')).toBe('English'); + // If the language code is not provided + expect(getLangName('')).toBe('Unavailable'); + }); + + test('should render props and text elements test for the page component', async () => { + const formData = { + firstName: 'Ansh', + lastName: 'Goyal', + email: 'ansh@gmail.com', + image: new File(['hello'], 'hello.png', { type: 'image/png' }), + address: 'abc', + countryCode: 'IN', + state: 'abc', + city: 'abc', + phoneNumber: '1234567890', + birthDate: '03/28/2022', + }; + renderMemberDetailScreen(link2); + + await wait(); + + expect(screen.queryByText('Loading data...')).not.toBeInTheDocument(); + expect(screen.getAllByText(/Email/i)).toBeTruthy(); + expect(screen.getByText('User')).toBeInTheDocument(); + const birthDateDatePicker = screen.getByTestId('birthDate'); + fireEvent.change(birthDateDatePicker, { + target: { value: formData.birthDate }, + }); + + userEvent.clear(screen.getByPlaceholderText(/First Name/i)); + userEvent.type( + screen.getByPlaceholderText(/First Name/i), + formData.firstName, + ); + + userEvent.clear(screen.getByPlaceholderText(/Last Name/i)); + userEvent.type( + screen.getByPlaceholderText(/Last Name/i), + formData.lastName, + ); + + userEvent.clear(screen.getByPlaceholderText(/Address/i)); + userEvent.type(screen.getByPlaceholderText(/Address/i), formData.address); + + userEvent.clear(screen.getByPlaceholderText(/Country Code/i)); + userEvent.type( + screen.getByPlaceholderText(/Country Code/i), + formData.countryCode, + ); + + userEvent.clear(screen.getByPlaceholderText(/State/i)); + userEvent.type(screen.getByPlaceholderText(/State/i), formData.state); + + userEvent.clear(screen.getByPlaceholderText(/City/i)); + userEvent.type(screen.getByPlaceholderText(/City/i), formData.city); + + userEvent.clear(screen.getByPlaceholderText(/Email/i)); + userEvent.type(screen.getByPlaceholderText(/Email/i), formData.email); + + userEvent.clear(screen.getByPlaceholderText(/Phone/i)); + userEvent.type(screen.getByPlaceholderText(/Phone/i), formData.phoneNumber); + + // userEvent.click(screen.getByPlaceholderText(/pluginCreationAllowed/i)); + // userEvent.selectOptions(screen.getByTestId('applangcode'), 'Français'); + // userEvent.upload(screen.getByLabelText(/Display Image:/i), formData.image); + await wait(); + + userEvent.click(screen.getByText(/Save Changes/i)); + + expect(screen.getByPlaceholderText(/First Name/i)).toHaveValue( + formData.firstName, + ); + expect(screen.getByPlaceholderText(/Last Name/i)).toHaveValue( + formData.lastName, + ); + expect(birthDateDatePicker).toHaveValue(formData.birthDate); + expect(screen.getByPlaceholderText(/Email/i)).toHaveValue(formData.email); + expect(screen.getByPlaceholderText(/First Name/i)).toBeInTheDocument(); + expect(screen.getByPlaceholderText(/Last Name/i)).toBeInTheDocument(); + expect(screen.getByPlaceholderText(/Email/i)).toBeInTheDocument(); + // expect(screen.getByText(/Display Image/i)).toBeInTheDocument(); + }); + + test('display admin', async () => { + renderMemberDetailScreen(link1); + await wait(); + expect(screen.queryByText('Loading data...')).not.toBeInTheDocument(); + expect(screen.getByText('Admin')).toBeInTheDocument(); + }); + + test('display super admin', async () => { + renderMemberDetailScreen(link3); + await wait(); + expect(screen.queryByText('Loading data...')).not.toBeInTheDocument(); + expect(screen.getByText('Super Admin')).toBeInTheDocument(); + }); + + test('Should display dicebear image if image is null', async () => { + renderMemberDetailScreen(link1); + + expect(screen.queryByText('Loading data...')).not.toBeInTheDocument(); + + const dicebearUrl = 'mocked-data-uri'; + + const userImage = await screen.findByTestId('userImageAbsent'); + expect(userImage).toBeInTheDocument(); + expect(userImage.getAttribute('src')).toBe(dicebearUrl); + }); + + test('Should display image if image is present', async () => { + renderMemberDetailScreen(link2); + + expect(screen.queryByText('Loading data...')).not.toBeInTheDocument(); + + const user = MOCKS2[0].result?.data?.user?.user; + const userImage = await screen.findByTestId('userImagePresent'); + expect(userImage).toBeInTheDocument(); + expect(userImage.getAttribute('src')).toBe(user?.image); + }); + + test('resetChangesBtn works properly', async () => { + renderMemberDetailScreen(link1); + + await waitFor(() => { + expect(screen.getByPlaceholderText(/Address/i)).toBeInTheDocument(); + }); + + userEvent.type(screen.getByPlaceholderText(/Address/i), 'random'); + userEvent.type(screen.getByPlaceholderText(/State/i), 'random'); + + userEvent.click(screen.getByTestId('resetChangesBtn')); + await wait(); + expect(screen.getByPlaceholderText(/First Name/i)).toHaveValue('Aditya'); + expect(screen.getByPlaceholderText(/Last Name/i)).toHaveValue('Agarwal'); + expect(screen.getByPlaceholderText(/Phone/i)).toHaveValue(''); + expect(screen.getByPlaceholderText(/Address/i)).toHaveValue(''); + expect(screen.getByPlaceholderText(/State/i)).toHaveValue(''); + expect(screen.getByPlaceholderText(/Country Code/i)).toHaveValue(''); + expect(screen.getByTestId('birthDate')).toHaveValue('03/14/2024'); + }); + + test('should be redirected to / if member id is undefined', async () => { + render( + + + + + + + + + , + ); + expect(window.location.pathname).toEqual('/'); + }); + + test('renders events attended card correctly and show a message', async () => { + renderMemberDetailScreen(link3); + await waitFor(() => { + expect(screen.getByText('Events Attended')).toBeInTheDocument(); + }); + // Check for empty state immediately + expect(screen.getByText('No Events Attended')).toBeInTheDocument(); + }); + + test('opens "Events Attended List" modal when View All button is clicked', async () => { + renderMemberDetailScreen(link2); + + await wait(); + + // Find and click the "View All" button + const viewAllButton = screen.getByText('View All'); + userEvent.click(viewAllButton); + + // Check if the modal with the title "Events Attended List" is now visible + const modalTitle = await screen.findByText('Events Attended List'); + expect(modalTitle).toBeInTheDocument(); + }); + + test('lists all the tags assigned to the user', async () => { + renderMemberDetailScreen(link1); + + await wait(); + + await waitFor(() => { + expect(screen.getAllByTestId('tagName')).toHaveLength(10); + }); + }); + + test('navigates to manage tag screen after clicking manage tag option', async () => { + renderMemberDetailScreen(link1); + + await wait(); + + await waitFor(() => { + expect(screen.getAllByTestId('tagName')[0]).toBeInTheDocument(); + }); + userEvent.click(screen.getAllByTestId('tagName')[0]); + + await waitFor(() => { + expect(screen.getByTestId('manageTagScreen')).toBeInTheDocument(); + }); + }); + + test('loads more assigned tags with infinite scroll', async () => { + renderMemberDetailScreen(link1); + + await wait(); + + // now scroll to the bottom of the div + const tagsAssignedScrollableDiv = screen.getByTestId( + 'tagsAssignedScrollableDiv', + ); + + // Get the initial number of tags loaded + const initialTagsAssignedLength = screen.getAllByTestId('tagName').length; + + // Set scroll position to the bottom + fireEvent.scroll(tagsAssignedScrollableDiv, { + target: { scrollY: tagsAssignedScrollableDiv.scrollHeight }, + }); + + await waitFor(() => { + const finalTagsAssignedLength = screen.getAllByTestId('tagName').length; + expect(finalTagsAssignedLength).toBeGreaterThan( + initialTagsAssignedLength, + ); + }); + }); + + test('opens and closes the unassign tag modal', async () => { + renderMemberDetailScreen(link1); + + 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('unassigns a tag from a member', async () => { + renderMemberDetailScreen(link1); + + 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, + ); + }); + }); +}); diff --git a/src/screens/MemberDetail/MemberDetail.test.tsx b/src/screens/MemberDetail/MemberDetail.test.tsx deleted file mode 100644 index 7b3707754c..0000000000 --- a/src/screens/MemberDetail/MemberDetail.test.tsx +++ /dev/null @@ -1,600 +0,0 @@ -import React from 'react'; -import { - act, - fireEvent, - render, - screen, - waitFor, -} from '@testing-library/react'; -import { MockedProvider } from '@apollo/react-testing'; -import userEvent from '@testing-library/user-event'; -import { BrowserRouter } from 'react-router-dom'; -import { Provider } from 'react-redux'; -import { store } from 'state/store'; -import { I18nextProvider } from 'react-i18next'; -import { USER_DETAILS } from 'GraphQl/Queries/Queries'; -import i18nForTest from 'utils/i18nForTest'; -import { StaticMockLink } from 'utils/StaticMockLink'; -import MemberDetail, { getLanguageName, prettyDate } from './MemberDetail'; -import { toast } from 'react-toastify'; - -const MOCKS1 = [ - { - request: { - query: USER_DETAILS, - variables: { - id: 'rishav-jha-mech', - }, - }, - result: { - data: { - user: { - __typename: 'UserData', - appUserProfile: { - _id: '1', - __typename: 'AppUserProfile', - adminFor: [ - { - __typename: 'Organization', - _id: '65e0df0906dd1228350cfd4a', - }, - { - __typename: 'Organization', - _id: '65e0e2abb92c9f3e29503d4e', - }, - ], - isSuperAdmin: false, - appLanguageCode: 'en', - createdEvents: [ - { - __typename: 'Event', - _id: '65e32a5b2a1f4288ca1f086a', - }, - ], - createdOrganizations: [ - { - __typename: 'Organization', - _id: '65e0df0906dd1228350cfd4a', - }, - { - __typename: 'Organization', - _id: '65e0e2abb92c9f3e29503d4e', - }, - ], - eventAdmin: [ - { - __typename: 'Event', - _id: '65e32a5b2a1f4288ca1f086a', - }, - ], - pluginCreationAllowed: true, - }, - user: { - _id: '1', - __typename: 'User', - createdAt: '2024-02-26T10:36:33.098Z', - email: 'adi790u@gmail.com', - firstName: 'Aditya', - image: null, - lastName: 'Agarwal', - gender: '', - birthDate: '2024-03-14', - educationGrade: '', - employmentStatus: '', - maritalStatus: '', - address: { - line1: '', - countryCode: '', - city: '', - state: '', - }, - phone: { - mobile: '', - }, - joinedOrganizations: [ - { - __typename: 'Organization', - _id: '65e0df0906dd1228350cfd4a', - }, - { - __typename: 'Organization', - _id: '65e0e2abb92c9f3e29503d4e', - }, - ], - membershipRequests: [], - organizationsBlockedBy: [], - registeredEvents: [ - { - __typename: 'Event', - _id: '65e32a5b2a1f4288ca1f086a', - }, - ], - }, - }, - }, - }, - }, -]; - -const MOCKS2 = [ - { - request: { - query: USER_DETAILS, - variables: { - id: 'rishav-jha-mech', - }, - }, - result: { - data: { - user: { - __typename: 'UserData', - appUserProfile: { - _id: '1', - __typename: 'AppUserProfile', - adminFor: [], - isSuperAdmin: false, - appLanguageCode: 'en', - createdEvents: [ - { - __typename: 'Event', - _id: '65e32a5b2a1f4288ca1f086a', - }, - ], - createdOrganizations: [ - { - __typename: 'Organization', - _id: '65e0df0906dd1228350cfd4a', - }, - { - __typename: 'Organization', - _id: '65e0e2abb92c9f3e29503d4e', - }, - ], - eventAdmin: [ - { - __typename: 'Event', - _id: '65e32a5b2a1f4288ca1f086a', - }, - ], - pluginCreationAllowed: true, - }, - user: { - _id: '1', - __typename: 'User', - createdAt: '2024-02-26T10:36:33.098Z', - email: 'adi790u@gmail.com', - firstName: 'Aditya', - image: 'https://placeholder.com/200x200', - lastName: 'Agarwal', - gender: '', - birthDate: '2024-03-14', - educationGrade: '', - employmentStatus: '', - maritalStatus: '', - address: { - line1: '', - countryCode: '', - city: '', - state: '', - }, - phone: { - mobile: '', - }, - joinedOrganizations: [ - { - __typename: 'Organization', - _id: '65e0df0906dd1228350cfd4a', - }, - { - __typename: 'Organization', - _id: '65e0e2abb92c9f3e29503d4e', - }, - ], - membershipRequests: [], - organizationsBlockedBy: [], - registeredEvents: [ - { - __typename: 'Event', - _id: '65e32a5b2a1f4288ca1f086a', - }, - ], - }, - }, - }, - }, - }, -]; -const MOCKS3 = [ - { - request: { - query: USER_DETAILS, - variables: { - id: 'rishav-jha-mech', - }, - }, - result: { - data: { - user: { - __typename: 'UserData', - appUserProfile: { - _id: '1', - __typename: 'AppUserProfile', - adminFor: [], - isSuperAdmin: true, - appLanguageCode: 'en', - createdEvents: [ - { - __typename: 'Event', - _id: '65e32a5b2a1f4288ca1f086a', - }, - ], - createdOrganizations: [ - { - __typename: 'Organization', - _id: '65e0df0906dd1228350cfd4a', - }, - { - __typename: 'Organization', - _id: '65e0e2abb92c9f3e29503d4e', - }, - ], - eventAdmin: [ - { - __typename: 'Event', - _id: '65e32a5b2a1f4288ca1f086a', - }, - ], - pluginCreationAllowed: true, - }, - user: { - _id: '1', - __typename: 'User', - createdAt: '2024-02-26T10:36:33.098Z', - email: 'adi790u@gmail.com', - firstName: 'Aditya', - image: 'https://placeholder.com/200x200', - lastName: 'Agarwal', - gender: '', - birthDate: '2024-03-14', - educationGrade: '', - employmentStatus: '', - maritalStatus: '', - address: { - line1: '', - countryCode: '', - city: '', - state: '', - }, - phone: { - mobile: '', - }, - joinedOrganizations: [ - { - __typename: 'Organization', - _id: '65e0df0906dd1228350cfd4a', - }, - { - __typename: 'Organization', - _id: '65e0e2abb92c9f3e29503d4e', - }, - ], - membershipRequests: [], - organizationsBlockedBy: [], - registeredEvents: [ - { - __typename: 'Event', - _id: '65e32a5b2a1f4288ca1f086a', - }, - ], - }, - }, - }, - }, - }, -]; - -const link1 = new StaticMockLink(MOCKS1, true); -const link2 = new StaticMockLink(MOCKS2, true); -const link3 = new StaticMockLink(MOCKS3, true); - -async function wait(ms = 20): Promise { - await act(() => new Promise((resolve) => setTimeout(resolve, ms))); -} - -jest.mock('@mui/x-date-pickers/DateTimePicker', () => { - return { - DateTimePicker: jest.requireActual( - '@mui/x-date-pickers/DesktopDateTimePicker', - ).DesktopDateTimePicker, - }; -}); - -jest.mock('react-toastify'); - -describe('MemberDetail', () => { - global.alert = jest.fn(); - - test('should render the elements', async () => { - const props = { - id: 'rishav-jha-mech', - }; - - render( - - - - - - - - - , - ); - - expect(screen.queryByText('Loading data...')).not.toBeInTheDocument(); - await wait(); - expect(screen.getAllByText(/Email/i)).toBeTruthy(); - expect(screen.getAllByText(/First name/i)).toBeTruthy(); - expect(screen.getAllByText(/Last name/i)).toBeTruthy(); - expect(screen.getAllByText(/Language/i)).toBeTruthy(); - expect(screen.getByText(/Plugin creation allowed/i)).toBeInTheDocument(); - expect(screen.getAllByText(/Joined on/i)).toBeTruthy(); - expect(screen.getAllByText(/Joined On/i)).toHaveLength(1); - expect(screen.getAllByText(/Personal Information/i)).toHaveLength(1); - expect(screen.getAllByText(/Profile Details/i)).toHaveLength(1); - expect(screen.getAllByText(/Actions/i)).toHaveLength(1); - expect(screen.getAllByText(/Contact Information/i)).toHaveLength(1); - }); - - test('prettyDate function should work properly', () => { - // If the date is provided - const datePretty = jest.fn(prettyDate); - expect(datePretty('2023-02-18T09:22:27.969Z')).toBe( - prettyDate('2023-02-18T09:22:27.969Z'), - ); - // If there's some error in formatting the date - expect(datePretty('')).toBe('Unavailable'); - }); - - test('getLanguageName function should work properly', () => { - const getLangName = jest.fn(getLanguageName); - // If the language code is provided - expect(getLangName('en')).toBe('English'); - // If the language code is not provided - expect(getLangName('')).toBe('Unavailable'); - }); - - test('should render props and text elements test for the page component', async () => { - const props = { - id: '1', - }; - - const formData = { - firstName: 'Ansh', - lastName: 'Goyal', - email: 'ansh@gmail.com', - image: new File(['hello'], 'hello.png', { type: 'image/png' }), - address: 'abc', - countryCode: 'IN', - state: 'abc', - city: 'abc', - phoneNumber: '1234567890', - birthDate: '03/28/2022', - }; - render( - - - - - - - - - , - ); - expect(screen.queryByText('Loading data...')).not.toBeInTheDocument(); - await wait(); - expect(screen.getAllByText(/Email/i)).toBeTruthy(); - expect(screen.getByText('User')).toBeInTheDocument(); - const birthDateDatePicker = screen.getByTestId('birthDate'); - fireEvent.change(birthDateDatePicker, { - target: { value: formData.birthDate }, - }); - - userEvent.type( - screen.getByPlaceholderText(/First Name/i), - formData.firstName, - ); - userEvent.type( - screen.getByPlaceholderText(/Last Name/i), - formData.lastName, - ); - userEvent.type(screen.getByPlaceholderText(/Address/i), formData.address); - userEvent.type( - screen.getByPlaceholderText(/Country Code/i), - formData.countryCode, - ); - userEvent.type(screen.getByPlaceholderText(/State/i), formData.state); - userEvent.type(screen.getByPlaceholderText(/City/i), formData.city); - userEvent.type(screen.getByPlaceholderText(/Email/i), formData.email); - userEvent.type(screen.getByPlaceholderText(/Phone/i), formData.phoneNumber); - userEvent.click(screen.getByPlaceholderText(/pluginCreationAllowed/i)); - userEvent.selectOptions(screen.getByTestId('applangcode'), 'Français'); - userEvent.upload(screen.getByLabelText(/Display Image:/i), formData.image); - await wait(); - - userEvent.click(screen.getByText(/Save Changes/i)); - - expect(screen.getByPlaceholderText(/First Name/i)).toHaveValue( - formData.firstName, - ); - expect(screen.getByPlaceholderText(/Last Name/i)).toHaveValue( - formData.lastName, - ); - expect(birthDateDatePicker).toHaveValue(formData.birthDate); - expect(screen.getByPlaceholderText(/Email/i)).toHaveValue(formData.email); - expect(screen.getByPlaceholderText(/First Name/i)).toBeInTheDocument(); - expect(screen.getByPlaceholderText(/Last Name/i)).toBeInTheDocument(); - expect(screen.getByPlaceholderText(/Email/i)).toBeInTheDocument(); - expect(screen.getByText(/Display Image/i)).toBeInTheDocument(); - }); - - test('should display warnings for blank form submission', async () => { - jest.spyOn(toast, 'warning'); - const props = { - id: '1', - toggleStateValue: jest.fn(), - }; - - render( - - - - - - - - - , - ); - - await wait(); - - userEvent.click(screen.getByText(/Save Changes/i)); - - 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', - }; - - render( - - - - - - - - - , - ); - - expect(screen.queryByText('Loading data...')).not.toBeInTheDocument(); - await wait(); - expect(screen.getByText('Admin')).toBeInTheDocument(); - }); - test('display super admin', async () => { - const props = { - id: 'rishav-jha-mech', - }; - - render( - - - - - - - - - , - ); - - expect(screen.queryByText('Loading data...')).not.toBeInTheDocument(); - await wait(); - expect(screen.getByText('Super Admin')).toBeInTheDocument(); - }); - - test('Should display dicebear image if image is null', async () => { - const props = { - id: 'rishav-jha-mech', - from: 'orglist', - }; - - render( - - - - - - - - - , - ); - expect(screen.queryByText('Loading data...')).not.toBeInTheDocument(); - - const dicebearUrl = `mocked-data-uri`; - - const userImage = await screen.findByTestId('userImageAbsent'); - expect(userImage).toBeInTheDocument(); - expect(userImage.getAttribute('src')).toBe(dicebearUrl); - }); - - test('Should display image if image is present', async () => { - const props = { - id: 'rishav-jha-mech', - from: 'orglist', - }; - - render( - - - - - - - - - , - ); - - expect(screen.queryByText('Loading data...')).not.toBeInTheDocument(); - - const user = MOCKS2[0].result?.data?.user?.user; - const userImage = await screen.findByTestId('userImagePresent'); - expect(userImage).toBeInTheDocument(); - expect(userImage.getAttribute('src')).toBe(user?.image); - }); - - test('should call setState with 2 when button is clicked', async () => { - const props = { - id: 'rishav-jha-mech', - }; - render( - - - - - - - - - , - ); - - expect(screen.queryByText('Loading data...')).not.toBeInTheDocument(); - - waitFor(() => userEvent.click(screen.getByText(/Edit Profile/i))); - }); - - test('should be redirected to / if member id is undefined', async () => { - render( - - - - - - - - - , - ); - expect(window.location.pathname).toEqual('/'); - }); -}); diff --git a/src/screens/MemberDetail/MemberDetail.tsx b/src/screens/MemberDetail/MemberDetail.tsx index 6d92ccbb4a..cc528a8de3 100644 --- a/src/screens/MemberDetail/MemberDetail.tsx +++ b/src/screens/MemberDetail/MemberDetail.tsx @@ -2,25 +2,22 @@ import React, { useEffect, useRef, useState } from 'react'; import { useMutation, useQuery } from '@apollo/client'; import Button from 'react-bootstrap/Button'; import { useTranslation } from 'react-i18next'; -import { useLocation } from 'react-router-dom'; -import { USER_DETAILS } from 'GraphQl/Queries/Queries'; -import styles from './MemberDetail.module.css'; +import { useLocation, useNavigate, useParams } from 'react-router-dom'; +import styles from '../../style/app.module.css'; import { languages } from 'utils/languages'; import { UPDATE_USER_MUTATION } from 'GraphQl/Mutations/mutations'; +import { USER_DETAILS } from 'GraphQl/Queries/Queries'; import { toast } from 'react-toastify'; import { errorHandler } from 'utils/errorHandler'; +import { Card, Row, Col } from 'react-bootstrap'; import Loader from 'components/Loader/Loader'; import useLocalStorage from 'utils/useLocalstorage'; import Avatar from 'components/Avatar/Avatar'; -import { - CalendarIcon, - DatePicker, - LocalizationProvider, -} from '@mui/x-date-pickers'; +import EventsAttendedByMember from '../../components/MemberDetail/EventsAttendedByMember'; +import MemberAttendedEventsModal from '../../components/MemberDetail/EventsAttendedMemberModal'; +import { DatePicker, LocalizationProvider } from '@mui/x-date-pickers'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; -import { Form } from 'react-bootstrap'; import convertToBase64 from 'utils/convertToBase64'; -import sanitizeHtml from 'sanitize-html'; import type { Dayjs } from 'dayjs'; import dayjs from 'dayjs'; import { @@ -30,9 +27,16 @@ import { employmentStatusEnum, } from 'utils/formEnumFields'; import DynamicDropDown from 'components/DynamicDropDown/DynamicDropDown'; +import type { InterfaceEvent } from 'components/EventManagement/EventAttendance/InterfaceEvents'; +import type { InterfaceTagData } from 'utils/interfaces'; +import InfiniteScroll from 'react-infinite-scroll-component'; +import InfiniteScrollLoader from 'components/InfiniteScrollLoader/InfiniteScrollLoader'; +import UnassignUserTagModal from 'screens/ManageTag/UnassignUserTagModal'; +import { UNASSIGN_USER_TAG } from 'GraphQl/Mutations/TagMutations'; +import { TAGS_QUERY_DATA_CHUNK_SIZE } from 'utils/organizationTagsUtils'; type MemberDetailProps = { - id?: string; // This is the userId + id?: string; }; /** @@ -48,11 +52,20 @@ const MemberDetail: React.FC = ({ id }): JSX.Element => { const { t } = useTranslation('translation', { keyPrefix: 'memberDetail', }); + const fileInputRef = useRef(null); const { t: tCommon } = useTranslation('common'); const location = useLocation(); const isMounted = useRef(true); const { getItem, setItem } = useLocalStorage(); + const [show, setShow] = useState(false); const currentUrl = location.state?.id || getItem('id') || id; + + const { orgId } = useParams(); + const navigate = useNavigate(); + + const [unassignUserTagModalIsOpen, setUnassignUserTagModalIsOpen] = + useState(false); + document.title = t('title'); const [formState, setFormState] = useState({ firstName: '', @@ -72,24 +85,33 @@ const MemberDetail: React.FC = ({ id }): JSX.Element => { country: '', pluginCreationAllowed: false, }); - // Handle date change const handleDateChange = (date: Dayjs | null): void => { if (date) { + setisUpdated(true); setFormState((prevState) => ({ ...prevState, - birthDate: dayjs(date).format('YYYY-MM-DD'), // Convert Dayjs object to JavaScript Date object + birthDate: dayjs(date).format('YYYY-MM-DD'), })); } }; + + /*istanbul ignore next*/ + const handleEditIconClick = (): void => { + fileInputRef.current?.click(); + }; const [updateUser] = useMutation(UPDATE_USER_MUTATION); - const { data: user, loading: loading } = useQuery(USER_DETAILS, { - variables: { id: currentUrl }, // For testing we are sending the id as a prop + const { + data: user, + loading, + refetch: refetchUserDetails, + fetchMore: fetchMoreAssignedTags, + } = useQuery(USER_DETAILS, { + variables: { id: currentUrl, first: TAGS_QUERY_DATA_CHUNK_SIZE }, }); const userData = user?.user; - + const [isUpdated, setisUpdated] = useState(false); useEffect(() => { - if (userData && isMounted) { - // console.log(userData); + if (userData && isMounted.current) { setFormState({ ...formState, firstName: userData?.user?.firstName, @@ -97,7 +119,7 @@ const MemberDetail: React.FC = ({ id }): JSX.Element => { email: userData?.user?.email, appLanguageCode: userData?.appUserProfile?.appLanguageCode, gender: userData?.user?.gender, - birthDate: userData?.user?.birthDate || '2020-03-14', + birthDate: userData?.user?.birthDate || ' ', grade: userData?.user?.educationGrade, empStatus: userData?.user?.employmentStatus, maritalStatus: userData?.user?.maritalStatus, @@ -111,7 +133,6 @@ const MemberDetail: React.FC = ({ id }): JSX.Element => { }); } }, [userData, user]); - useEffect(() => { // check component is mounted or not return () => { @@ -119,75 +140,120 @@ const MemberDetail: React.FC = ({ id }): JSX.Element => { }; }, []); - const handleChange = (e: React.ChangeEvent): void => { - const { name, value } = e.target; - // setFormState({ - // ...formState, - // [name]: value, - // }); - // console.log(name, value); - setFormState((prevState) => ({ - ...prevState, - [name]: value, - })); - // console.log(formState); + const tagsAssigned = + userData?.user?.tagsAssignedWith.edges.map( + (edge: { node: InterfaceTagData; cursor: string }) => edge.node, + ) ?? /* istanbul ignore next */ []; + + const loadMoreAssignedTags = (): void => { + fetchMoreAssignedTags({ + variables: { + first: TAGS_QUERY_DATA_CHUNK_SIZE, + after: + user?.user?.user?.tagsAssignedWith?.pageInfo?.endCursor ?? + /* istanbul ignore next */ + null, + }, + updateQuery: (prevResult, { fetchMoreResult }) => { + if (!fetchMoreResult) /* istanbul ignore next */ return prevResult; + + return { + user: { + ...prevResult.user, + user: { + ...prevResult.user.user, + tagsAssignedWith: { + edges: [ + ...prevResult.user.user.tagsAssignedWith.edges, + ...fetchMoreResult.user.user.tagsAssignedWith.edges, + ], + pageInfo: fetchMoreResult.user.user.tagsAssignedWith.pageInfo, + totalCount: fetchMoreResult.user.user.tagsAssignedWith.pageInfo, + }, + }, + }, + }; + }, + }); + }; + + const [unassignUserTag] = useMutation(UNASSIGN_USER_TAG); + const [unassignTagId, setUnassignTagId] = useState(null); + + const handleUnassignUserTag = async (): Promise => { + try { + await unassignUserTag({ + variables: { + tagId: unassignTagId, + userId: currentUrl, + }, + }); + + refetchUserDetails(); + toggleUnassignUserTagModal(); + toast.success(t('successfullyUnassigned')); + } catch (error: unknown) { + /* istanbul ignore next */ + if (error instanceof Error) { + toast.error(error.message); + } + } }; - // const handlePhoneChange = (e: React.ChangeEvent): void => { - // const { name, value } = e.target; - // setFormState({ - // ...formState, - // phoneNumber: { - // ...formState.phoneNumber, - // [name]: value, - // }, - // }); - // // console.log(formState); - // }; + const toggleUnassignUserTagModal = (): void => { + if (unassignUserTagModalIsOpen) { + setUnassignTagId(null); + } + setUnassignUserTagModalIsOpen(!unassignUserTagModalIsOpen); + }; - const handleToggleChange = (e: React.ChangeEvent): void => { - // console.log(e.target.checked); - const { name, checked } = e.target; - setFormState((prevState) => ({ - ...prevState, - [name]: checked, - })); - // console.log(formState); + const handleChange = async ( + e: React.ChangeEvent, + ): Promise => { + const { name, value } = e.target; + /*istanbul ignore next*/ + if ( + name === 'photo' && + 'files' in e.target && + e.target.files && + e.target.files[0] + ) { + const file = e.target.files[0]; + const base64 = await convertToBase64(file); + setFormState((prevState) => ({ + ...prevState, + image: base64 as string, + })); + } else { + setFormState((prevState) => ({ + ...prevState, + [name]: value, + })); + } + setisUpdated(true); + }; + const handleEventsAttendedModal = (): void => { + setShow(!show); }; const loginLink = async (): Promise => { try { - // console.log(formState); const firstName = formState.firstName; const lastName = formState.lastName; const email = formState.email; // const appLanguageCode = formState.appLanguageCode; const image = formState.image; // const gender = formState.gender; - let toSubmit = true; - if (firstName.trim().length == 0 || !firstName) { - toast.warning('First Name cannot be blank!'); - toSubmit = false; - } - if (lastName.trim().length == 0 || !lastName) { - toast.warning('Last Name cannot be blank!'); - toSubmit = false; - } - if (email.trim().length == 0 || !email) { - toast.warning('Email cannot be blank!'); - toSubmit = false; - } - if (!toSubmit) return; try { const { data } = await updateUser({ variables: { - //! Currently only some fields are supported by the api id: currentUrl, ...formState, }, }); /* istanbul ignore next */ if (data) { + setisUpdated(false); if (getItem('id') === currentUrl) { setItem('FirstName', firstName); setItem('LastName', lastName); @@ -208,346 +274,471 @@ const MemberDetail: React.FC = ({ id }): JSX.Element => { } } }; + const resetChanges = (): void => { + /*istanbul ignore next*/ + setFormState({ + firstName: userData?.user?.firstName || '', + lastName: userData?.user?.lastName || '', + email: userData?.user?.email || '', + appLanguageCode: userData?.appUserProfile?.appLanguageCode || '', + image: userData?.user?.image || '', + gender: userData?.user?.gender || '', + empStatus: userData?.user?.employmentStatus || '', + maritalStatus: userData?.user?.maritalStatus || '', + phoneNumber: userData?.user?.phone?.mobile || '', + address: userData?.user?.address?.line1 || '', + country: userData?.user?.address?.countryCode || '', + city: userData?.user?.address?.city || '', + state: userData?.user?.address?.state || '', + birthDate: userData?.user?.birthDate || '', + grade: userData?.user?.educationGrade || '', + pluginCreationAllowed: + userData?.appUserProfile?.pluginCreationAllowed || false, + }); + setisUpdated(false); + }; if (loading) { return ; } - const sanitizedSrc = sanitizeHtml(formState.image, { - allowedTags: ['img'], - allowedAttributes: { - img: ['src', 'alt'], - }, - }); - return ( -
-
-
- {/* Personal */} -
-
+ )} + + + + +

{t('personalDetailsHeading')}

+ +
+ +
+ {formState?.image ? ( +
+ User + e.key === 'Enter' && handleEditIconClick() + } + /> +
+ ) : ( +
+ + +
+ )} +
-
-
-

{tCommon('firstName')}

+ + + -
-
-

{tCommon('lastName')}

+ + + -
-
-

{t('gender')}

-
- -
-
-
-

{t('birthDate')}

-
- -
-
-
-

{t('educationGrade')}

+ + + -
-
-

{t('employmentStatus')}

+ + + + + + + -
-
-

{t('maritalStatus')}

+ + + -
-

-

-
-
- {/* Contact Info */} -
-
-

{t('contactInfoHeading')}

-
-
-
-

{t('phone')}

- -
-
-

{tCommon('email')}

+ + + + + + + + +

{t('contactInfoHeading')}

+
+ + + + -
-
-

{tCommon('address')}

+ + + -
-
-

{t('countryCode')}

+ + + -
-
-

{t('city')}

+ + + -
-
-

{t('state')}

+ + + -
-
-
-
-
- {/* Personal */} -
-
+ + + + + + + + + {isUpdated && ( + + +
-
-
- {formState.image ? ( - - ) : ( - <> - - - )} -
-
-

{formState?.firstName}

-
-

- {userData?.appUserProfile?.isSuperAdmin - ? 'Super Admin' - : userData?.appUserProfile?.adminFor.length > 0 - ? 'Admin' - : 'User'} -

-
-

{formState.email}

-

- - Joined on {prettyDate(userData?.user?.createdAt)} -

-
-
-
- - {/* Actions */} -
-
+
-
-
-
- -

- {`${t('pluginCreationAllowed')} (API not supported yet)`} -

-
+ {tCommon('saveChanges')} + + + + )} + + + + + + +

+ {t('tagsAssigned')} +

+
+ + {!tagsAssigned.length ? ( +
+ {t('noTagsAssigned')}
-
-
-
- + {'Unassign'} + +
+ {index + 1 !== tagsAssigned.length && ( +
+ )}
-
-
- - -
-
-
-
-
+ ))} + + )} + + + + + + + +

+ {t('eventsAttended')} +

-
-
-
-
+ + + {!userData?.user.eventsAttended?.length ? ( +
+ {t('noeventsAttended')} +
+ ) : ( + userData.user.eventsAttended.map( + (event: InterfaceEvent, index: number) => ( + + + + ), + ) + )} +
+ + + + + {/* Unassign User Tag Modal */} + ); }; + export const prettyDate = (param: string): string => { const date = new Date(param); if (date?.toDateString() === 'Invalid Date') { @@ -567,4 +758,5 @@ export const getLanguageName = (code: string): string => { }); return language; }; + export default MemberDetail; diff --git a/src/screens/MemberDetail/MemberDetailMocks.ts b/src/screens/MemberDetail/MemberDetailMocks.ts new file mode 100644 index 0000000000..df72ee703c --- /dev/null +++ b/src/screens/MemberDetail/MemberDetailMocks.ts @@ -0,0 +1,536 @@ +import { UNASSIGN_USER_TAG } from 'GraphQl/Mutations/TagMutations'; +import { USER_DETAILS } from 'GraphQl/Queries/Queries'; +import { TAGS_QUERY_DATA_CHUNK_SIZE } from 'utils/organizationTagsUtils'; + +export const MOCKS1 = [ + { + request: { + query: USER_DETAILS, + variables: { + id: 'rishav-jha-mech', + first: TAGS_QUERY_DATA_CHUNK_SIZE, + }, + }, + result: { + data: { + user: { + __typename: 'UserData', + appUserProfile: { + _id: '1', + __typename: 'AppUserProfile', + adminFor: [ + { + __typename: 'Organization', + _id: '65e0df0906dd1228350cfd4a', + }, + { + __typename: 'Organization', + _id: '65e0e2abb92c9f3e29503d4e', + }, + ], + isSuperAdmin: false, + appLanguageCode: 'en', + createdEvents: [ + { + __typename: 'Event', + _id: '65e32a5b2a1f4288ca1f086a', + }, + ], + createdOrganizations: [ + { + __typename: 'Organization', + _id: '65e0df0906dd1228350cfd4a', + }, + { + __typename: 'Organization', + _id: '65e0e2abb92c9f3e29503d4e', + }, + ], + eventAdmin: [ + { + __typename: 'Event', + _id: '65e32a5b2a1f4288ca1f086a', + }, + ], + pluginCreationAllowed: true, + }, + user: { + _id: '1', + __typename: 'User', + createdAt: '2024-02-26T10:36:33.098Z', + email: 'adi790u@gmail.com', + firstName: 'Aditya', + image: null, + lastName: 'Agarwal', + gender: '', + birthDate: '2024-03-14', + educationGrade: '', + employmentStatus: '', + maritalStatus: '', + address: { + line1: '', + countryCode: '', + city: '', + state: '', + }, + phone: { + mobile: '', + }, + eventsAttended: [], + joinedOrganizations: [ + { + __typename: 'Organization', + _id: '65e0df0906dd1228350cfd4a', + }, + { + __typename: 'Organization', + _id: '65e0e2abb92c9f3e29503d4e', + }, + ], + tagsAssignedWith: { + edges: [ + { + node: { + _id: '1', + name: 'userTag 1', + parentTag: null, + }, + cursor: '1', + }, + { + node: { + _id: '2', + name: 'userTag 2', + parentTag: null, + }, + cursor: '2', + }, + { + node: { + _id: '3', + name: 'userTag 3', + parentTag: null, + }, + cursor: '3', + }, + { + node: { + _id: '4', + name: 'userTag 4', + parentTag: null, + }, + cursor: '4', + }, + { + node: { + _id: '5', + name: 'userTag 5', + parentTag: null, + }, + cursor: '5', + }, + { + node: { + _id: '6', + name: 'userTag 6', + parentTag: null, + }, + cursor: '6', + }, + { + node: { + _id: '7', + name: 'userTag 7', + parentTag: null, + }, + cursor: '7', + }, + { + node: { + _id: '8', + name: 'userTag 8', + parentTag: null, + }, + cursor: '8', + }, + { + node: { + _id: '9', + name: 'userTag 9', + parentTag: null, + }, + cursor: '9', + }, + { + node: { + _id: '10', + name: 'userTag 10', + parentTag: null, + }, + cursor: '10', + }, + ], + pageInfo: { + startCursor: '1', + endCursor: '10', + hasNextPage: true, + hasPreviousPage: false, + }, + totalCount: 12, + }, + membershipRequests: [], + organizationsBlockedBy: [], + registeredEvents: [ + { + __typename: 'Event', + _id: '65e32a5b2a1f4288ca1f086a', + }, + ], + }, + }, + }, + }, + }, + { + request: { + query: USER_DETAILS, + variables: { + id: 'rishav-jha-mech', + first: TAGS_QUERY_DATA_CHUNK_SIZE, + after: '10', + }, + }, + result: { + data: { + user: { + __typename: 'UserData', + appUserProfile: { + _id: '1', + __typename: 'AppUserProfile', + adminFor: [ + { + __typename: 'Organization', + _id: '65e0df0906dd1228350cfd4a', + }, + { + __typename: 'Organization', + _id: '65e0e2abb92c9f3e29503d4e', + }, + ], + isSuperAdmin: false, + appLanguageCode: 'en', + createdEvents: [ + { + __typename: 'Event', + _id: '65e32a5b2a1f4288ca1f086a', + }, + ], + createdOrganizations: [ + { + __typename: 'Organization', + _id: '65e0df0906dd1228350cfd4a', + }, + { + __typename: 'Organization', + _id: '65e0e2abb92c9f3e29503d4e', + }, + ], + eventAdmin: [ + { + __typename: 'Event', + _id: '65e32a5b2a1f4288ca1f086a', + }, + ], + pluginCreationAllowed: true, + }, + user: { + _id: '1', + __typename: 'User', + createdAt: '2024-02-26T10:36:33.098Z', + email: 'adi790u@gmail.com', + firstName: 'Aditya', + image: null, + lastName: 'Agarwal', + gender: '', + birthDate: '2024-03-14', + educationGrade: '', + employmentStatus: '', + maritalStatus: '', + address: { + line1: '', + countryCode: '', + city: '', + state: '', + }, + phone: { + mobile: '', + }, + eventsAttended: [], + joinedOrganizations: [ + { + __typename: 'Organization', + _id: '65e0df0906dd1228350cfd4a', + }, + { + __typename: 'Organization', + _id: '65e0e2abb92c9f3e29503d4e', + }, + ], + tagsAssignedWith: { + edges: [ + { + node: { + _id: '11', + name: 'userTag 11', + parentTag: null, + }, + cursor: '11', + }, + { + node: { + _id: '12', + name: 'subTag 1', + parentTag: { _id: '1' }, + }, + cursor: '12', + }, + ], + pageInfo: { + startCursor: '11', + endCursor: '12', + hasNextPage: false, + hasPreviousPage: true, + }, + totalCount: 12, + }, + membershipRequests: [], + organizationsBlockedBy: [], + registeredEvents: [ + { + __typename: 'Event', + _id: '65e32a5b2a1f4288ca1f086a', + }, + ], + }, + }, + }, + }, + }, + { + request: { + query: UNASSIGN_USER_TAG, + variables: { + tagId: '1', + userId: 'rishav-jha-mech', + }, + }, + result: { + data: { + unassignUserTag: { + _id: '1', + }, + }, + }, + }, +]; + +export const MOCKS2 = [ + { + request: { + query: USER_DETAILS, + variables: { + id: 'rishav-jha-mech', + first: TAGS_QUERY_DATA_CHUNK_SIZE, + }, + }, + result: { + data: { + user: { + __typename: 'UserData', + appUserProfile: { + _id: '1', + __typename: 'AppUserProfile', + adminFor: [], + isSuperAdmin: false, + appLanguageCode: 'en', + createdEvents: [ + { + __typename: 'Event', + _id: '65e32a5b2a1f4288ca1f086a', + }, + ], + createdOrganizations: [ + { + __typename: 'Organization', + _id: '65e0df0906dd1228350cfd4a', + }, + { + __typename: 'Organization', + _id: '65e0e2abb92c9f3e29503d4e', + }, + ], + eventAdmin: [ + { + __typename: 'Event', + _id: '65e32a5b2a1f4288ca1f086a', + }, + ], + pluginCreationAllowed: true, + }, + user: { + _id: '1', + __typename: 'User', + createdAt: '2024-02-26T10:36:33.098Z', + email: 'adi790u@gmail.com', + firstName: 'Aditya', + image: 'https://placeholder.com/200x200', + lastName: 'Agarwal', + gender: '', + birthDate: '2024-03-14', + educationGrade: '', + employmentStatus: '', + maritalStatus: '', + address: { + line1: '', + countryCode: '', + city: '', + state: '', + }, + phone: { + mobile: '', + }, + joinedOrganizations: [ + { + __typename: 'Organization', + _id: '65e0df0906dd1228350cfd4a', + }, + { + __typename: 'Organization', + _id: '65e0e2abb92c9f3e29503d4e', + }, + ], + tagsAssignedWith: { + edges: [], + pageInfo: { + startCursor: null, + endCursor: null, + hasNextPage: false, + hasPreviousPage: false, + }, + totalCount: 0, + }, + eventsAttended: [{ _id: 'event1' }, { _id: 'event2' }], + membershipRequests: [], + organizationsBlockedBy: [], + registeredEvents: [ + { + __typename: 'Event', + _id: '65e32a5b2a1f4288ca1f086a', + }, + ], + }, + }, + }, + }, + }, +]; +export const MOCKS3 = [ + { + request: { + query: USER_DETAILS, + variables: { + id: 'rishav-jha-mech', + first: TAGS_QUERY_DATA_CHUNK_SIZE, + }, + }, + result: { + data: { + user: { + __typename: 'UserData', + appUserProfile: { + _id: '1', + __typename: 'AppUserProfile', + adminFor: [], + isSuperAdmin: true, + appLanguageCode: 'en', + createdEvents: [ + { + __typename: 'Event', + _id: '65e32a5b2a1f4288ca1f086a', + }, + ], + createdOrganizations: [ + { + __typename: 'Organization', + _id: '65e0df0906dd1228350cfd4a', + }, + { + __typename: 'Organization', + _id: '65e0e2abb92c9f3e29503d4e', + }, + ], + eventAdmin: [ + { + __typename: 'Event', + _id: '65e32a5b2a1f4288ca1f086a', + }, + ], + pluginCreationAllowed: true, + }, + user: { + _id: '1', + __typename: 'User', + createdAt: '2024-02-26T10:36:33.098Z', + email: 'adi790u@gmail.com', + firstName: 'Aditya', + image: 'https://placeholder.com/200x200', + lastName: 'Agarwal', + gender: '', + birthDate: '2024-03-14', + educationGrade: '', + employmentStatus: '', + maritalStatus: '', + address: { + line1: '', + countryCode: '', + city: '', + state: '', + }, + phone: { + mobile: '', + }, + tagsAssignedWith: { + edges: [], + pageInfo: { + startCursor: null, + endCursor: null, + hasNextPage: false, + hasPreviousPage: false, + }, + totalCount: 0, + }, + eventsAttended: [], + joinedOrganizations: [ + { + __typename: 'Organization', + _id: '65e0df0906dd1228350cfd4a', + }, + { + __typename: 'Organization', + _id: '65e0e2abb92c9f3e29503d4e', + }, + ], + membershipRequests: [], + organizationsBlockedBy: [], + registeredEvents: [ + { + __typename: 'Event', + _id: '65e32a5b2a1f4288ca1f086a', + }, + ], + }, + }, + }, + }, + }, +]; diff --git a/src/screens/OrgContribution/OrgContribution.module.css b/src/screens/OrgContribution/OrgContribution.module.css deleted file mode 100644 index 7ca9333bf7..0000000000 --- a/src/screens/OrgContribution/OrgContribution.module.css +++ /dev/null @@ -1,261 +0,0 @@ -.navbarbg { - height: 60px; - background-color: white; - display: flex; - margin-bottom: 30px; - z-index: 1; - position: relative; - flex-direction: row; - justify-content: space-between; - box-shadow: 0px 0px 8px 2px #c8c8c8; -} - -.logo { - color: #707070; - margin-left: 0; - display: flex; - align-items: center; - text-decoration: none; -} - -.logo img { - margin-top: 0px; - margin-left: 10px; - height: 64px; - width: 70px; -} - -.logo > strong { - line-height: 1.5rem; - margin-left: -5px; - font-family: sans-serif; - font-size: 19px; - color: #707070; -} -.mainpage { - display: flex; - flex-direction: row; -} -.sidebar { - z-index: 0; - padding-top: 5px; - margin: 0; - height: 100%; -} -.sidebar:after { - background-color: #f7f7f7; - position: absolute; - width: 2px; - height: 600px; - top: 10px; - left: 94%; - display: block; -} -.sidebarsticky { - padding-left: 45px; - margin-top: 7px; -} -.sidebarsticky > p { - margin-top: -10px; -} - -.navitem { - padding-left: 27%; - padding-top: 12px; - padding-bottom: 12px; - cursor: pointer; -} - -.logintitle { - color: #707070; - font-weight: 600; - font-size: 20px; - margin-bottom: 30px; - padding-bottom: 5px; - border-bottom: 3px solid #31bb6b; - width: 15%; -} -.searchtitle { - color: #707070; - font-weight: 600; - font-size: 18px; - margin-bottom: 20px; - padding-bottom: 5px; - border-bottom: 3px solid #31bb6b; - width: 60%; -} -.logintitleadmin { - color: #707070; - font-weight: 600; - font-size: 18px; - margin-top: 50px; - margin-bottom: 40px; - padding-bottom: 5px; - border-bottom: 3px solid #31bb6b; - width: 30%; -} -.admindetails { - display: flex; - justify-content: space-between; -} -.admindetails > p { - margin-top: -12px; - margin-right: 30px; -} - -.mainpageright > hr { - margin-top: 20px; - width: 100%; - margin-left: -15px; - margin-right: -15px; - margin-bottom: 20px; -} -.justifysp { - display: flex; - justify-content: space-between; -} -@media screen and (max-width: 575.5px) { - .justifysp { - padding-left: 55px; - display: flex; - justify-content: space-between; - width: 100%; - } -} -.addbtn { - border: 1px solid #e8e5e5; - box-shadow: 0 2px 2px #e8e5e5; - border-radius: 5px; - background-color: #31bb6b; - width: 15%; - height: 40px; - font-size: 16px; - color: white; - outline: none; - font-weight: 600; - cursor: pointer; - transition: - transform 0.2s, - box-shadow 0.2s; -} -.flexdir { - display: flex; - flex-direction: row; - justify-content: space-between; - border: none; -} - -.form_wrapper { - margin-top: 27px; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - position: absolute; - display: flex; - flex-direction: column; - width: 30%; - padding: 40px 30px; - background: #ffffff; - border-color: #e8e5e5; - border-width: 5px; - border-radius: 10px; -} - -.form_wrapper form { - display: flex; - align-items: left; - justify-content: left; - flex-direction: column; -} -.logintitleinvite { - color: #707070; - font-weight: 600; - font-size: 20px; - margin-bottom: 20px; - padding-bottom: 5px; - border-bottom: 3px solid #31bb6b; - width: 40%; -} -.cancel > i { - margin-top: 5px; - transform: scale(1.2); - cursor: pointer; - color: #707070; -} -.modalbody { - width: 50px; -} -.greenregbtn { - margin: 1rem 0 0; - margin-top: 10px; - 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%; -} -.sidebarsticky > input { - text-decoration: none; - margin-bottom: 50px; - border-color: #e8e5e5; - width: 80%; - border-radius: 7px; - padding-top: 5px; - padding-bottom: 5px; - padding-right: 10px; - padding-left: 10px; - box-shadow: none; -} - -.loader, -.loader:after { - border-radius: 50%; - width: 10em; - height: 10em; -} -.loader { - margin: 60px auto; - margin-top: 35vh !important; - font-size: 10px; - position: relative; - text-indent: -9999em; - border-top: 1.1em solid rgba(255, 255, 255, 0.2); - border-right: 1.1em solid rgba(255, 255, 255, 0.2); - border-bottom: 1.1em solid rgba(255, 255, 255, 0.2); - border-left: 1.1em solid #febc59; - -webkit-transform: translateZ(0); - -ms-transform: translateZ(0); - transform: translateZ(0); - -webkit-animation: load8 1.1s infinite linear; - animation: load8 1.1s infinite linear; -} -@-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/screens/OrgContribution/OrgContribution.test.tsx b/src/screens/OrgContribution/OrgContribution.spec.tsx similarity index 80% rename from src/screens/OrgContribution/OrgContribution.test.tsx rename to src/screens/OrgContribution/OrgContribution.spec.tsx index f9f63c6807..f12057a626 100644 --- a/src/screens/OrgContribution/OrgContribution.test.tsx +++ b/src/screens/OrgContribution/OrgContribution.spec.tsx @@ -1,9 +1,9 @@ -import React, { act } from 'react'; +import React from 'react'; import { MockedProvider } from '@apollo/react-testing'; import { render } from '@testing-library/react'; import { Provider } from 'react-redux'; import { BrowserRouter } from 'react-router-dom'; -import 'jest-location-mock'; +import { vi, describe, test, expect } from 'vitest'; import { I18nextProvider } from 'react-i18next'; import OrgContribution from './OrgContribution'; @@ -12,15 +12,20 @@ import i18nForTest from 'utils/i18nForTest'; import { StaticMockLink } from 'utils/StaticMockLink'; const link = new StaticMockLink([], true); async function wait(ms = 100): Promise { - await act(() => { - return new Promise((resolve) => { - setTimeout(resolve, ms); - }); + await new Promise((resolve) => { + setTimeout(resolve, ms); }); } describe('Organisation Contribution Page', () => { test('should render props and text elements test for the screen', async () => { + Object.defineProperty(window, 'location', { + value: { + assign: vi.fn(), + }, + writable: true, + }); + window.location.assign('/orglist'); const { container } = render( @@ -37,11 +42,10 @@ describe('Organisation Contribution Page', () => { expect(container.textContent).not.toBe('Loading data...'); await wait(); - expect(container.textContent).toMatch('Filter by Name'); expect(container.textContent).toMatch('Filter by Trans. ID'); expect(container.textContent).toMatch('Recent Stats'); expect(container.textContent).toMatch('Contribution'); - expect(window.location).toBeAt('/orglist'); + expect(window.location.assign).toHaveBeenCalledWith('/orglist'); }); }); diff --git a/src/screens/OrgContribution/OrgContribution.tsx b/src/screens/OrgContribution/OrgContribution.tsx index db155cdb47..e2061f5587 100644 --- a/src/screens/OrgContribution/OrgContribution.tsx +++ b/src/screens/OrgContribution/OrgContribution.tsx @@ -2,11 +2,10 @@ import React from 'react'; import Col from 'react-bootstrap/Col'; import Row from 'react-bootstrap/Row'; import { useTranslation } from 'react-i18next'; - import ContriStats from 'components/ContriStats/ContriStats'; import OrgContriCards from 'components/OrgContriCards/OrgContriCards'; import { Form } from 'react-bootstrap'; -import styles from './OrgContribution.module.css'; +import styles from '../../style/app.module.css'; /** * The `orgContribution` component displays the contributions to an organization. @@ -14,7 +13,7 @@ import styles from './OrgContribution.module.css'; * Additionally, it shows recent contribution statistics and a list of contribution cards. * */ -function orgContribution(): JSX.Element { +function OrgContribution(): JSX.Element { // Hook to get translation functions and translation text const { t } = useTranslation('translation', { keyPrefix: 'orgContribution', @@ -83,4 +82,4 @@ function orgContribution(): JSX.Element { ); } -export default orgContribution; +export default OrgContribution; diff --git a/src/screens/OrgList/OrgList.module.css b/src/screens/OrgList/OrgList.module.css deleted file mode 100644 index 9da1ecbb70..0000000000 --- a/src/screens/OrgList/OrgList.module.css +++ /dev/null @@ -1,323 +0,0 @@ -.btnsContainer { - display: flex; - margin: 2.5rem 0 2.5rem 0; -} - -.btnsContainer .btnsBlock { - display: flex; -} - -.orgCreationBtn { - width: 100%; - border: None; -} - -.enableEverythingBtn { - width: 100%; - border: None; -} - -.pluginStoreBtn { - width: 100%; - background-color: white; - color: #31bb6b; - border: 0.5px solid #31bb6b; -} - -.pluginStoreBtn:hover, -.pluginStoreBtn:focus { - background-color: #dfe1e2 !important; - color: #31bb6b !important; - border-color: #31bb6b !important; -} - -.line::before { - content: ''; - display: inline-block; - width: 100px; - border-top: 1px solid #000; - margin: 0 10px; -} - -.line::before { - left: 0; -} - -.line::after { - right: 0; -} - -.flexContainer { - display: flex; - justify-content: center; - align-items: center; - width: 100%; -} - -.orText { - display: block; - position: absolute; - top: calc(-0.7rem + 0.5rem); - left: calc(50% - 2.6rem); - margin: 0 auto; - padding: 0.5rem 2rem; - z-index: 100; - background: var(--bs-white); - color: var(--bs-secondary); -} -.sampleOrgSection { - display: grid; - grid-template-columns: repeat(1, 1fr); - row-gap: 1em; -} - -.sampleOrgCreationBtn { - width: 100%; - background-color: transparent; - color: #707070; - border-color: #707070; - display: flex; - justify-content: center; - align-items: center; -} - -.sampleHover:hover { - border-color: grey; - color: grey; -} - -.sampleOrgSection { - font-family: Arial, Helvetica, sans-serif; - width: 100%; - display: grid; - grid-auto-columns: repeat(1, 1fr); - justify-content: center; - flex-direction: column; - align-items: center; -} - -.sampleModalTitle { - background-color: green; -} - -.btnsContainer .btnsBlock button { - margin-left: 1rem; - display: flex; - justify-content: center; - align-items: center; -} - -.btnsContainer .input { - flex: 1; - position: relative; -} - -.btnsContainer input { - outline: 1px solid var(--bs-gray-400); -} - -.btnsContainer .input button { - width: 52px; -} - -.listBox { - display: flex; - flex-wrap: wrap; - overflow: unset !important; -} - -.listBox .itemCard { - width: 50%; -} - -.notFound { - flex: 1; - display: flex; - justify-content: center; - align-items: center; - flex-direction: column; -} - -@media (max-width: 1440px) { - .contract { - padding-left: calc(250px + 2rem + 1.5rem); - } - - .listBox .itemCard { - width: 100%; - } -} - -@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%; - } -} - -/* Loading OrgList CSS */ -.itemCard .loadingWrapper { - background-color: var(--bs-white); - margin: 0.5rem; - height: calc(120px + 2rem); - padding: 1rem; - border-radius: 8px; - outline: 1px solid var(--bs-gray-200); - position: relative; -} - -.itemCard .loadingWrapper .innerContainer { - display: flex; -} - -.itemCard .loadingWrapper .innerContainer .orgImgContainer { - width: 120px; - height: 120px; - border-radius: 4px; -} - -.itemCard .loadingWrapper .innerContainer .content { - flex: 1; - display: flex; - flex-direction: column; - margin-left: 1rem; -} - -.titlemodaldialog { - color: #707070; - font-size: 20px; - margin-bottom: 20px; - padding-bottom: 5px; -} - -form label { - font-weight: bold; - padding-bottom: 1px; - font-size: 14px; - color: #707070; -} - -form > input { - display: block; - margin-bottom: 20px; - border: 1px solid #e8e5e5; - box-shadow: 2px 1px #e8e5e5; - padding: 10px 20px; - border-radius: 5px; - background: none; - width: 100%; - transition: all 0.3s ease-in-out; - -webkit-transition: all 0.3s ease-in-out; - -moz-transition: all 0.3s ease-in-out; - -ms-transition: all 0.3s ease-in-out; - -o-transition: all 0.3s ease-in-out; -} - -.itemCard .loadingWrapper .innerContainer .content h5 { - height: 24px; - width: 60%; - margin-bottom: 0.8rem; -} - -.modalbody { - width: 50px; -} - -.pluginStoreBtnContainer { - display: flex; - gap: 1rem; -} - -.itemCard .loadingWrapper .innerContainer .content h6[title='Location'] { - display: block; - width: 45%; - height: 18px; -} - -.itemCard .loadingWrapper .innerContainer .content h6 { - display: block; - width: 30%; - height: 16px; - margin-bottom: 0.8rem; -} - -.itemCard .loadingWrapper .button { - position: absolute; - height: 48px; - width: 92px; - bottom: 1rem; - right: 1rem; - z-index: 1; -} - -@media (max-width: 450px) { - .itemCard .loadingWrapper { - height: unset; - margin: 0.5rem 0; - padding: 1.25rem 1.5rem; - } - - .itemCard .loadingWrapper .innerContainer { - flex-direction: column; - } - - .itemCard .loadingWrapper .innerContainer .orgImgContainer { - height: 200px; - width: 100%; - margin-bottom: 0.8rem; - } - - .itemCard .loadingWrapper .innerContainer .content { - margin-left: 0; - } - - .itemCard .loadingWrapper .button { - bottom: 0; - right: 0; - border-radius: 0.5rem; - position: relative; - margin-left: auto; - display: block; - } -} diff --git a/src/screens/OrgList/OrgList.test.tsx b/src/screens/OrgList/OrgList.test.tsx index 5b889ff07d..2b2809c7c9 100644 --- a/src/screens/OrgList/OrgList.test.tsx +++ b/src/screens/OrgList/OrgList.test.tsx @@ -44,11 +44,11 @@ async function wait(ms = 100): Promise { afterEach(() => { localStorage.clear(); cleanup(); + jest.clearAllMocks(); }); describe('Organisations Page testing as SuperAdmin', () => { setItem('id', '123'); - const link = new StaticMockLink(MOCKS, true); const link2 = new StaticMockLink(MOCKS_EMPTY, true); const link3 = new StaticMockLink(MOCKS_WITH_ERROR, true); @@ -475,7 +475,6 @@ describe('Organisations Page testing as SuperAdmin', () => { describe('Organisations Page testing as Admin', () => { const link = new StaticMockLink(MOCKS_ADMIN, true); - test('Create organization modal should not be present in the page for Admin', async () => { setItem('id', '123'); setItem('SuperAdmin', false); @@ -501,35 +500,47 @@ describe('Organisations Page testing as Admin', () => { setItem('SuperAdmin', false); setItem('AdminFor', [{ name: 'adi', _id: 'a0', image: '' }]); - await act(async () => { - render( - - - - - - - - - , - ); - - await wait(); - }); - const sortDropdown = await waitFor(() => screen.getByTestId('sort')); + render( + + + + + + + + + , + ); + + await wait(); + + const sortDropdown = screen.getByTestId('sort'); expect(sortDropdown).toBeInTheDocument(); const sortToggle = screen.getByTestId('sortOrgs'); - fireEvent.click(sortToggle); - const latestOption = await waitFor(() => screen.getByTestId('latest')); + await act(async () => { + fireEvent.click(sortToggle); + }); + + const latestOption = screen.getByTestId('latest'); - fireEvent.click(latestOption); + await act(async () => { + fireEvent.click(latestOption); + }); expect(sortDropdown).toBeInTheDocument(); - fireEvent.click(sortToggle); + + await act(async () => { + fireEvent.click(sortToggle); + }); + const oldestOption = await waitFor(() => screen.getByTestId('oldest')); - fireEvent.click(oldestOption); + + await act(async () => { + fireEvent.click(oldestOption); + }); + expect(sortDropdown).toBeInTheDocument(); }); }); diff --git a/src/screens/OrgList/OrgList.tsx b/src/screens/OrgList/OrgList.tsx index 7023bfa9b1..f30bb8f1ea 100644 --- a/src/screens/OrgList/OrgList.tsx +++ b/src/screens/OrgList/OrgList.tsx @@ -27,7 +27,8 @@ import type { InterfaceUserType, } from 'utils/interfaces'; import useLocalStorage from 'utils/useLocalstorage'; -import styles from './OrgList.module.css'; +// import styles from '../../style/app.module.css'; +import styles from '../../style/app.module.css'; import OrganizationModal from './OrganizationModal'; function orgList(): JSX.Element { @@ -38,7 +39,6 @@ function orgList(): JSX.Element { function openDialogModal(redirectOrgId: string): void { setDialogRedirectOrgId(redirectOrgId); - // console.log(redirectOrgId, dialogRedirectOrgId); setdialogModalIsOpen(true); } @@ -49,7 +49,7 @@ function orgList(): JSX.Element { function closeDialogModal(): void { setdialogModalIsOpen(false); } - const toggleDialogModal = /* istanbul ignore next */ (): void => + const toggleDialogModal = (): void => setdialogModalIsOpen(!dialogModalisOpen); document.title = t('title'); @@ -148,7 +148,6 @@ function orgList(): JSX.Element { setIsLoading(loading && isLoadingMore); }, [loading]); - /* istanbul ignore next */ const isAdminForCurrentOrg = ( currentOrg: InterfaceOrgConnectionInfoType, ): boolean => { @@ -205,7 +204,6 @@ function orgList(): JSX.Element { }, }); - /* istanbul ignore next */ if (data) { toast.success('Congratulation the Organization is created'); refetchOrgs(); @@ -230,17 +228,16 @@ function orgList(): JSX.Element { toggleModal(); } } catch (error: unknown) { - /* istanbul ignore next */ errorHandler(t, error); } }; - /* istanbul ignore next */ if (errorList || errorUser) { + errorHandler(t, errorList || errorUser); + localStorage.clear(); window.location.assign('/'); } - /* istanbul ignore next */ const resetAllParams = (): void => { refetchOrgs({ filter: '', @@ -252,7 +249,6 @@ function orgList(): JSX.Element { sethasMore(true); }; - /* istanbul ignore next */ const handleSearch = (value: string): void => { setSearchByName(value); if (value === '') { @@ -280,7 +276,7 @@ function orgList(): JSX.Element { const inputValue = inputElement?.value || ''; handleSearch(inputValue); }; - /* istanbul ignore next */ + const loadMoreOrganizations = (): void => { console.log('loadMoreOrganizations'); setIsLoadingMore(true); @@ -336,12 +332,12 @@ function orgList(): JSX.Element { return ( <> {/* Buttons Container */} -
+
-
+
} - /> - - - - - - , - ); -}; - -describe('Testing Organization Action Items Screen', () => { - beforeAll(() => { - jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useParams: () => ({ orgId: 'orgId', eventId: 'eventId' }), - })); - }); - - afterAll(() => { - jest.clearAllMocks(); - }); - - it('should redirect to fallback URL if URL params are undefined', async () => { - render( - - - - - - } - /> -
} - /> - - - - - , - ); - await waitFor(() => { - expect(screen.getByTestId('paramsError')).toBeInTheDocument(); - }); - }); - - it('should render Organization Action Items screen', async () => { - renderOrganizationActionItems(link1); - await waitFor(() => { - expect(screen.getByTestId('searchBy')).toBeInTheDocument(); - expect(screen.getByText('John Doe')).toBeInTheDocument(); - expect(screen.getByText('Jane Doe')).toBeInTheDocument(); - }); - }); - - it('Sort Action Items descending by dueDate', async () => { - renderOrganizationActionItems(link1); - - const sortBtn = await screen.findByTestId('sort'); - expect(sortBtn).toBeInTheDocument(); - - // Sort by dueDate_DESC - fireEvent.click(sortBtn); - await waitFor(() => { - expect(screen.getByTestId('dueDate_DESC')).toBeInTheDocument(); - }); - fireEvent.click(screen.getByTestId('dueDate_DESC')); - await waitFor(() => { - expect(screen.getAllByTestId('categoryName')[0]).toHaveTextContent( - 'Category 2', - ); - }); - }); - - it('Sort Action Items ascending by dueDate', async () => { - renderOrganizationActionItems(link1); - - const sortBtn = await screen.findByTestId('sort'); - expect(sortBtn).toBeInTheDocument(); - - // Sort by dueDate_ASC - fireEvent.click(sortBtn); - await waitFor(() => { - expect(screen.getByTestId('dueDate_ASC')).toBeInTheDocument(); - }); - fireEvent.click(screen.getByTestId('dueDate_ASC')); - await waitFor(() => { - expect(screen.getAllByTestId('categoryName')[0]).toHaveTextContent( - 'Category 1', - ); - }); - }); - - it('Filter Action Items by status (All/Pending)', async () => { - renderOrganizationActionItems(link1); - - 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 Pending - fireEvent.click(filterBtn); - await waitFor(() => { - expect(screen.getByTestId('statusPending')).toBeInTheDocument(); - }); - fireEvent.click(screen.getByTestId('statusPending')); - await waitFor(() => { - expect(screen.queryByText('Category 1')).toBeNull(); - expect(screen.getByText('Category 2')).toBeInTheDocument(); - }); - }); - - it('Filter Action Items by status (Completed)', async () => { - renderOrganizationActionItems(link1); - - const filterBtn = await screen.findByTestId('filter'); - expect(filterBtn).toBeInTheDocument(); - - fireEvent.click(filterBtn); - await waitFor(() => { - expect(screen.getByTestId('statusCompleted')).toBeInTheDocument(); - }); - fireEvent.click(screen.getByTestId('statusCompleted')); - await waitFor(() => { - expect(screen.getByText('Category 1')).toBeInTheDocument(); - expect(screen.queryByText('Category 2')).toBeNull(); - }); - }); - - it('open and close Item modal (create)', async () => { - renderOrganizationActionItems(link1); - - const addItemBtn = await screen.findByTestId('createActionItemBtn'); - expect(addItemBtn).toBeInTheDocument(); - userEvent.click(addItemBtn); - - await waitFor(() => - expect(screen.getAllByText(t.createActionItem)).toHaveLength(2), - ); - userEvent.click(screen.getByTestId('modalCloseBtn')); - await waitFor(() => - expect(screen.queryByTestId('modalCloseBtn')).toBeNull(), - ); - }); - - it('open and close Item modal (view)', async () => { - renderOrganizationActionItems(link1); - - const viewItemBtn = await screen.findByTestId('viewItemBtn1'); - expect(viewItemBtn).toBeInTheDocument(); - userEvent.click(viewItemBtn); - - await waitFor(() => - expect(screen.getByText(t.actionItemDetails)).toBeInTheDocument(), - ); - userEvent.click(screen.getByTestId('modalCloseBtn')); - await waitFor(() => - expect(screen.queryByTestId('modalCloseBtn')).toBeNull(), - ); - }); - - it('open and closes Item modal (edit)', async () => { - renderOrganizationActionItems(link1); - - const editItemBtn = await screen.findByTestId('editItemBtn1'); - await waitFor(() => expect(editItemBtn).toBeInTheDocument()); - userEvent.click(editItemBtn); - - await waitFor(() => - expect(screen.getAllByText(t.updateActionItem)).toHaveLength(2), - ); - userEvent.click(screen.getByTestId('modalCloseBtn')); - await waitFor(() => - expect(screen.queryByTestId('modalCloseBtn')).toBeNull(), - ); - }); - - it('open and closes Item modal (delete)', async () => { - renderOrganizationActionItems(link1); - - const deleteItemBtn = await screen.findByTestId('deleteItemBtn1'); - expect(deleteItemBtn).toBeInTheDocument(); - userEvent.click(deleteItemBtn); - - await waitFor(() => - expect(screen.getByText(t.deleteActionItem)).toBeInTheDocument(), - ); - userEvent.click(screen.getByTestId('modalCloseBtn')); - await waitFor(() => - expect(screen.queryByTestId('modalCloseBtn')).toBeNull(), - ); - }); - - it('open and closes Item modal (update status)', async () => { - renderOrganizationActionItems(link1); - - const statusCheckbox = await screen.findByTestId('statusCheckbox1'); - expect(statusCheckbox).toBeInTheDocument(); - userEvent.click(statusCheckbox); - - await waitFor(() => - expect(screen.getByText(t.actionItemStatus)).toBeInTheDocument(), - ); - userEvent.click(screen.getByTestId('modalCloseBtn')); - await waitFor(() => - expect(screen.queryByTestId('modalCloseBtn')).toBeNull(), - ); - }); - - it('Search action items by assignee', async () => { - renderOrganizationActionItems(link1); - - const searchByToggle = await screen.findByTestId('searchByToggle'); - expect(searchByToggle).toBeInTheDocument(); - - userEvent.click(searchByToggle); - await waitFor(() => { - expect(screen.getByTestId('assignee')).toBeInTheDocument(); - }); - - userEvent.click(screen.getByTestId('assignee')); - - const searchInput = await screen.findByTestId('searchBy'); - expect(searchInput).toBeInTheDocument(); - - userEvent.type(searchInput, 'John'); - userEvent.click(screen.getByTestId('searchBtn')); - await waitFor(() => { - expect(screen.getByText('Category 1')).toBeInTheDocument(); - expect(screen.queryByText('Category 2')).toBeNull(); - }); - }); - - it('Search action items by category', async () => { - renderOrganizationActionItems(link1); - - const searchByToggle = await screen.findByTestId('searchByToggle'); - expect(searchByToggle).toBeInTheDocument(); - - userEvent.click(searchByToggle); - await waitFor(() => { - expect(screen.getByTestId('category')).toBeInTheDocument(); - }); - - userEvent.click(screen.getByTestId('category')); - - const searchInput = await screen.findByTestId('searchBy'); - 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 action items by name and clear the input by backspace', async () => { - renderOrganizationActionItems(link1); - - const searchInput = await screen.findByTestId('searchBy'); - 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 action items by name on press of ENTER', async () => { - renderOrganizationActionItems(link1); - - const searchInput = await screen.findByTestId('searchBy'); - expect(searchInput).toBeInTheDocument(); - - userEvent.type(searchInput, 'John'); - 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 () => { - renderOrganizationActionItems(link3); - await waitFor(() => { - expect(screen.getByTestId('searchBy')).toBeInTheDocument(); - expect(screen.getByText(t.noActionItems)).toBeInTheDocument(); - }); - }); - - it('should render the Action Item Categories Screen with error', async () => { - renderOrganizationActionItems(link2); - await waitFor(() => { - expect(screen.getByTestId('errorMsg')).toBeInTheDocument(); - }); - }); -}); diff --git a/src/screens/OrganizationActionItems/OrganizationActionItems.tsx b/src/screens/OrganizationActionItems/OrganizationActionItems.tsx index ba48f212e0..6061ba7e7d 100644 --- a/src/screens/OrganizationActionItems/OrganizationActionItems.tsx +++ b/src/screens/OrganizationActionItems/OrganizationActionItems.tsx @@ -19,14 +19,14 @@ import type { InterfaceActionItemInfo, InterfaceActionItemList, } from 'utils/interfaces'; -import styles from './OrganizationActionItems.module.css'; +import styles from '../../style/app.module.css'; import Loader from 'components/Loader/Loader'; import { DataGrid, type GridCellParams, type GridColDef, } from '@mui/x-data-grid'; -import { Chip, Stack } from '@mui/material'; +import { Chip, debounce, Stack } from '@mui/material'; import ItemViewModal from './ItemViewModal'; import ItemModal from './ItemModal'; import ItemDeleteModal from './ItemDeleteModal'; @@ -46,27 +46,6 @@ enum ModalState { STATUS = 'status', } -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', - }, -}; - /** * Component for managing and displaying action items within an organization. * @@ -157,6 +136,11 @@ function organizationActionItems(): JSX.Element { [actionItemsData], ); + const debouncedSearch = useMemo( + () => debounce((value: string) => setSearchTerm(value), 300), + [], + ); + if (actionItemsLoading) { return ; } @@ -167,8 +151,6 @@ function organizationActionItems(): JSX.Element {
{tErrors('errorLoading', { entity: 'Action Items' })} -
- {`${actionItemsError.message}`}
); @@ -185,32 +167,58 @@ function organizationActionItems(): JSX.Element { sortable: false, headerClassName: `${styles.tableHeader}`, renderCell: (params: GridCellParams) => { - const { _id, firstName, lastName, image } = params.row.assignee; + const { _id, firstName, lastName, image } = + params.row.assigneeUser || params.row.assignee?.user || {}; + return ( -
- {image ? ( - Assignee + <> + {params.row.assigneeType !== 'EventVolunteerGroup' ? ( + <> +
+ {image ? ( + Assignee + ) : ( +
+ +
+ )} + {firstName + ' ' + lastName} +
+ ) : ( -
- -
+ <> +
+
+ +
+ {params.row.assigneeGroup?.name as string} +
+ )} - {params.row.assignee.firstName + ' ' + params.row.assignee.lastName} -
+ ); }, }, @@ -255,8 +263,8 @@ function organizationActionItems(): JSX.Element { }, }, { - field: 'allotedHours', - headerName: 'Alloted Hours', + field: 'allottedHours', + headerName: 'Allotted Hours', align: 'center', headerAlign: 'center', sortable: false, @@ -264,7 +272,9 @@ function organizationActionItems(): JSX.Element { flex: 1, renderCell: (params: GridCellParams) => { return ( -
{params.row.allotedHours ?? '-'}
+
+ {params.row.allottedHours ?? '-'} +
); }, }, @@ -297,10 +307,10 @@ function organizationActionItems(): JSX.Element { return ( <>
-
+
handleModalClick(null, ModalState.SAME)} - style={{ marginTop: '11px' }} + className={styles.createButton} data-testid="createActionItemBtn" > @@ -497,7 +498,29 @@ function organizationActionItems(): JSX.Element { ), }} - sx={dataGridStyle} + sx={{ + borderRadius: '20px', + backgroundColor: 'EAEBEF)', + '& .MuiDataGrid-row': { + backgroundColor: '#eff1f7', + '&:focus-within': { + // outline: '2px solid #000', + outlineOffset: '-2px', + }, + }, + '& .MuiDataGrid-row:hover': { + backgroundColor: '#EAEBEF', + boxShadow: '0 0 0 1px rgba(0, 0, 0, 0.1)', + }, + '& .MuiDataGrid-row.Mui-hovered': { + backgroundColor: '#EAEBEF', + boxShadow: '0 0 0 1px rgba(0, 0, 0, 0.1)', + }, + '& .MuiDataGrid-cell:focus': { + // outline: '2px solid #000', + // outlineOffset: '-2px', + }, + }} getRowClassName={() => `${styles.rowBackground}`} autoHeight rowHeight={65} @@ -514,32 +537,35 @@ function organizationActionItems(): JSX.Element { isOpen={modalState[ModalState.SAME]} hide={() => closeModal(ModalState.SAME)} orgId={orgId} + eventId={eventId} actionItemsRefetch={actionItemsRefetch} actionItem={actionItem} editMode={modalMode === 'edit'} /> - closeModal(ModalState.DELETE)} - actionItem={actionItem} - actionItemsRefetch={actionItemsRefetch} - /> - - closeModal(ModalState.STATUS)} - actionItemsRefetch={actionItemsRefetch} - /> - {/* View Modal */} {actionItem && ( - closeModal(ModalState.VIEW)} - item={actionItem} - /> + <> + closeModal(ModalState.VIEW)} + item={actionItem} + /> + + closeModal(ModalState.STATUS)} + actionItemsRefetch={actionItemsRefetch} + /> + + closeModal(ModalState.DELETE)} + actionItem={actionItem} + actionItemsRefetch={actionItemsRefetch} + /> + )}
); diff --git a/src/screens/OrganizationActionItems/testObject.mocks.ts b/src/screens/OrganizationActionItems/testObject.mocks.ts new file mode 100644 index 0000000000..d43f574e8c --- /dev/null +++ b/src/screens/OrganizationActionItems/testObject.mocks.ts @@ -0,0 +1,402 @@ +import { + EVENT_VOLUNTEER_GROUP_LIST, + EVENT_VOLUNTEER_LIST, +} from 'GraphQl/Queries/EventVolunteerQueries'; +import { + ACTION_ITEM_CATEGORY_LIST, + MEMBERS_LIST, +} from 'GraphQl/Queries/Queries'; +import type { InterfaceActionItemInfo } from 'utils/interfaces'; + +export const actionItemCategory1 = { + _id: 'actionItemCategoryId1', + name: 'Category 1', +}; + +export const actionItemCategory2 = { + _id: 'actionItemCategoryId2', + name: 'Category 2', +}; + +export const baseActionItem = { + assigner: { + _id: 'userId', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + }, + creator: { + _id: 'userId', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + __typename: 'User', + }, +}; + +export const itemWithVolunteer: InterfaceActionItemInfo = { + _id: 'actionItemId1', + assigneeType: 'EventVolunteer', + assignee: { + _id: 'volunteerId1', + hasAccepted: true, + hoursVolunteered: 12, + assignments: [], + groups: [], + user: { + _id: 'userId1', + firstName: 'John', + lastName: 'Doe', + image: null, + }, + }, + assigneeUser: null, + assigneeGroup: null, + preCompletionNotes: 'Notes 1', + postCompletionNotes: 'Cmp Notes 1', + assignmentDate: new Date('2024-08-27'), + dueDate: new Date('2044-08-30'), + completionDate: new Date('2044-09-03'), + isCompleted: true, + event: null, + allottedHours: 24, + actionItemCategory: actionItemCategory1, + ...baseActionItem, +}; + +export const itemWithVolunteerImage: InterfaceActionItemInfo = { + _id: 'actionItemId1b', + assigneeType: 'EventVolunteer', + assignee: { + _id: 'volunteerId1', + hasAccepted: true, + hoursVolunteered: 12, + assignments: [], + groups: [], + user: { + _id: 'userId1', + firstName: 'John', + lastName: 'Doe', + image: 'user-image', + }, + }, + assigneeUser: null, + assigneeGroup: null, + preCompletionNotes: 'Notes 1', + postCompletionNotes: 'Cmp Notes 1', + assignmentDate: new Date('2024-08-27'), + dueDate: new Date('2044-08-30'), + completionDate: new Date('2044-09-03'), + isCompleted: true, + event: null, + allottedHours: 24, + actionItemCategory: actionItemCategory1, + ...baseActionItem, +}; + +export const itemWithUser: InterfaceActionItemInfo = { + _id: 'actionItemId2', + assigneeType: 'User', + assigneeUser: { + _id: 'userId1', + firstName: 'Jane', + lastName: 'Doe', + image: null, + }, + assignee: null, + assigneeGroup: null, + preCompletionNotes: 'Notes 2', + postCompletionNotes: null, + assignmentDate: new Date('2024-08-27'), + dueDate: new Date('2044-09-30'), + completionDate: new Date('2044-10-03'), + isCompleted: false, + event: null, + allottedHours: null, + actionItemCategory: actionItemCategory2, + ...baseActionItem, +}; + +export const itemWithUserImage: InterfaceActionItemInfo = { + _id: 'actionItemId2b', + assigneeType: 'User', + assigneeUser: { + _id: 'userId1', + firstName: 'Jane', + lastName: 'Doe', + image: 'user-image', + }, + assignee: null, + assigneeGroup: null, + preCompletionNotes: 'Notes 2', + postCompletionNotes: null, + assignmentDate: new Date('2024-08-27'), + dueDate: new Date('2044-09-30'), + completionDate: new Date('2044-10-03'), + isCompleted: false, + event: null, + allottedHours: null, + actionItemCategory: actionItemCategory2, + ...baseActionItem, +}; + +export const itemWithGroup: InterfaceActionItemInfo = { + _id: 'actionItemId3', + assigneeType: 'EventVolunteerGroup', + assigneeUser: null, + assignee: null, + assigneeGroup: { + _id: 'volunteerGroupId1', + name: 'Group 1', + description: 'Group 1 Description', + volunteersRequired: 10, + event: { + _id: 'eventId1', + }, + assignments: [], + volunteers: [], + createdAt: '2024-08-27', + creator: { + _id: 'userId1', + firstName: 'John', + lastName: 'Doe', + image: null, + }, + leader: { + _id: 'userId1', + firstName: 'John', + lastName: 'Doe', + image: null, + }, + }, + preCompletionNotes: 'Notes 1', + postCompletionNotes: 'Cmp Notes 1', + assignmentDate: new Date('2024-08-27'), + dueDate: new Date('2044-08-30'), + completionDate: new Date('2044-09-03'), + isCompleted: true, + event: null, + allottedHours: 24, + actionItemCategory: actionItemCategory1, + ...baseActionItem, +}; + +export const memberListQuery = { + request: { + query: MEMBERS_LIST, + variables: { id: 'orgId' }, + }, + result: { + data: { + organizations: [ + { + _id: 'orgId', + members: [ + { + _id: 'userId1', + firstName: 'Harve', + lastName: 'Lance', + email: 'harve@example.com', + image: '', + organizationsBlockedBy: [], + createdAt: '2024-02-14', + }, + { + _id: 'userId2', + firstName: 'Wilt', + lastName: 'Shepherd', + email: 'wilt@example.com', + image: '', + organizationsBlockedBy: [], + createdAt: '2024-02-14', + }, + ], + }, + ], + }, + }, +}; + +export const volunteerListQuery = [ + { + request: { + query: EVENT_VOLUNTEER_LIST, + variables: { where: { eventId: 'eventId', hasAccepted: true } }, + }, + result: { + data: { + getEventVolunteers: [ + { + _id: 'volunteerId1', + hasAccepted: true, + hoursVolunteered: 0, + user: { + _id: 'userId1', + firstName: 'Teresa', + lastName: 'Bradley', + image: null, + }, + assignments: [], + groups: [ + { + _id: 'groupId1', + name: 'group1', + volunteers: [ + { + _id: 'volunteerId1', + }, + ], + }, + ], + }, + { + _id: 'volunteerId2', + hasAccepted: true, + hoursVolunteered: 0, + user: { + _id: 'userId3', + firstName: 'Bruce', + lastName: 'Graza', + image: null, + }, + assignments: [], + groups: [], + }, + ], + }, + }, + }, + { + request: { + query: EVENT_VOLUNTEER_LIST, + variables: { where: { hasAccepted: true } }, + }, + result: { + data: { + getEventVolunteers: [], + }, + }, + }, +]; + +export const groupListQuery = [ + { + request: { + query: EVENT_VOLUNTEER_GROUP_LIST, + variables: { where: { eventId: 'eventId' } }, + }, + result: { + data: { + getEventVolunteerGroups: [ + { + _id: 'groupId1', + name: 'group1', + description: 'desc', + volunteersRequired: 10, + createdAt: '2024-10-27T15:34:15.889Z', + creator: { + _id: 'userId2', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + }, + leader: { + _id: 'userId1', + firstName: 'Teresa', + lastName: 'Bradley', + image: null, + }, + volunteers: [ + { + _id: 'volunteerId1', + user: { + _id: 'userId1', + firstName: 'Teresa', + lastName: 'Bradley', + image: null, + }, + }, + ], + assignments: [], + event: { + _id: 'eventId', + }, + }, + { + _id: 'groupId2', + name: 'group2', + description: 'desc', + volunteersRequired: 10, + createdAt: '2024-10-27T15:34:15.889Z', + creator: { + _id: 'userId2', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + }, + leader: { + _id: 'userId1', + firstName: 'Teresa', + lastName: 'Bradley', + image: null, + }, + volunteers: [], + assignments: [], + event: { + _id: 'eventId', + }, + }, + ], + }, + }, + }, + { + request: { + query: EVENT_VOLUNTEER_GROUP_LIST, + variables: { where: { eventId: undefined } }, + }, + result: { + data: { + getEventVolunteerGroups: [], + }, + }, + }, +]; + +export const actionItemCategoryListQuery = { + request: { + query: ACTION_ITEM_CATEGORY_LIST, + variables: { + organizationId: 'orgId', + where: { is_disabled: false }, + }, + }, + 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', + }, + }, + ], + }, + }, +}; diff --git a/src/screens/OrganizationDashboard/OrganizationDashboard.module.css b/src/screens/OrganizationDashboard/OrganizationDashboard.module.css deleted file mode 100644 index f9423de686..0000000000 --- a/src/screens/OrganizationDashboard/OrganizationDashboard.module.css +++ /dev/null @@ -1,29 +0,0 @@ -.cardHeader { - padding: 1.25rem 1rem 1rem 1rem; - border-bottom: 1px solid var(--bs-gray-200); - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 10px; -} - -.cardHeader .cardTitle { - font-size: 1.2rem; - font-weight: 600; -} - -.cardBody { - min-height: 180px; - padding-top: 0; - max-height: 570px; - overflow-y: scroll; - width: 100%; - max-width: 400px; -} - -.cardBody .emptyContainer { - display: flex; - height: 180px; - justify-content: center; - align-items: center; -} diff --git a/src/screens/OrganizationDashboard/OrganizationDashboard.spec.tsx b/src/screens/OrganizationDashboard/OrganizationDashboard.spec.tsx new file mode 100644 index 0000000000..6fd27ce429 --- /dev/null +++ b/src/screens/OrganizationDashboard/OrganizationDashboard.spec.tsx @@ -0,0 +1,315 @@ +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 { 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, useParams } from 'react-router-dom'; +import { store } from 'state/store'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import i18n from 'utils/i18nForTest'; +import OrganizationDashboard from './OrganizationDashboard'; +import type { ApolloLink } from '@apollo/client'; +import { MOCKS, EMPTY_MOCKS, ERROR_MOCKS } from './OrganizationDashboardMocks'; +import { toast } from 'react-toastify'; +import { vi } from 'vitest'; + +/** + * This file contains unit tests for the OrganizationDashboard component. + * + * The tests cover: + * - Behavior when URL parameters are undefined, including redirection to fallback URLs. + * - Rendering of key sections, such as dashboard cards, upcoming events, latest posts, membership requests, and volunteer rankings. + * - Functionality of user interactions with dashboard elements (e.g., navigation via clicks on cards and buttons). + * - Handling of scenarios with empty data or errors in GraphQL responses. + * - Integration with mocked GraphQL queries and toast notifications. + * + * These tests are implemented using Vitest for test execution and MockedProvider for mocking GraphQL queries. + */ + +vi.mock('react-toastify', () => ({ + toast: { + success: vi.fn(), + error: vi.fn(), + }, +})); + +const link1 = new StaticMockLink(MOCKS); +const link2 = new StaticMockLink(ERROR_MOCKS); +const link3 = new StaticMockLink(EMPTY_MOCKS); +const t = { + ...JSON.parse( + JSON.stringify(i18n.getDataByLanguage('en')?.translation.dashboard ?? {}), + ), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.common ?? {})), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.errors ?? {})), +}; + +const renderOrganizationDashboard = (link: ApolloLink): RenderResult => { + return render( + + + + + + + } + /> +
} + /> +
} + /> +
} + /> +
} + /> +
} + /> +
} + /> +
} + /> +
} + /> + + + + + + , + ); +}; + +describe('Testing Organization Dashboard Screen', () => { + beforeAll(() => { + vi.mock('react-router-dom', async () => { + const originalModule = await vi.importActual('react-router-dom'); + return { + ...originalModule, + useParams: vi.fn(), + }; + }); + }); + + afterAll(() => { + vi.clearAllMocks(); + }); + + it('should redirect to fallback URL if URL params are undefined', async () => { + vi.mocked(useParams).mockReturnValue({}); + render( + + + + + +
} + /> + } /> + + + + + , + ); + await waitFor(() => { + expect(window.location.pathname).toBe('/'); + }); + await waitFor(() => { + expect(screen.getByTestId('paramsError')).toBeInTheDocument(); + }); + }); + + it('should render Organization Dashboard screen', async () => { + vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' }); + renderOrganizationDashboard(link1); + + // First wait for the dashboard to fully load + await waitFor(() => { + expect(screen.getByText(t.upcomingEvents)).toBeInTheDocument(); + }); + + // Dashboard cards + const membersBtn = await screen.findByText(t.members); + expect(membersBtn).toBeInTheDocument(); + expect(screen.getByText(t.admins)).toBeInTheDocument(); + expect(screen.getByText(t.posts)).toBeInTheDocument(); + expect(screen.getByText(t.events)).toBeInTheDocument(); + expect(screen.getByText(t.blockedUsers)).toBeInTheDocument(); + + // Upcoming events - Use a more flexible matcher + expect(screen.getByText(/Event 1/i, { exact: false })).toBeInTheDocument(); + + // Latest posts + expect(screen.getByText(t.latestPosts)).toBeInTheDocument(); + expect(screen.getByText('postone')).toBeInTheDocument(); + + // Membership requests + expect(screen.getByText(t.membershipRequests)).toBeInTheDocument(); + expect(screen.getByText('Jane Doe')).toBeInTheDocument(); + + // Volunteer rankings + expect(screen.getByText(t.volunteerRankings)).toBeInTheDocument(); + expect(screen.getByText('Teresa Bradley')).toBeInTheDocument(); + }); + + it('Click People Card', async () => { + vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' }); + renderOrganizationDashboard(link1); + const membersBtn = await screen.findByText(t.members); + expect(membersBtn).toBeInTheDocument(); + + userEvent.click(membersBtn); + await waitFor(() => { + expect(screen.getByTestId('orgpeople')).toBeInTheDocument(); + }); + }); + + it('Click Admin Card', async () => { + vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' }); + renderOrganizationDashboard(link1); + const adminsBtn = await screen.findByText(t.admins); + expect(adminsBtn).toBeInTheDocument(); + }); +}); + +it('Click Post Card', async () => { + vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' }); + renderOrganizationDashboard(link1); + const postsBtn = await screen.findByText(t.posts); + expect(postsBtn).toBeInTheDocument(); + + userEvent.click(postsBtn); + await waitFor(() => { + expect(screen.getByTestId('orgpost')).toBeInTheDocument(); + }); +}); + +it('Click Events Card', async () => { + vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' }); + renderOrganizationDashboard(link1); + const eventsBtn = await screen.findByText(t.events); + expect(eventsBtn).toBeInTheDocument(); + + userEvent.click(eventsBtn); + await waitFor(() => { + expect(screen.getByTestId('orgevents')).toBeInTheDocument(); + }); +}); + +it('Click Blocked Users Card', async () => { + vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' }); + renderOrganizationDashboard(link1); + const blockedUsersBtn = await screen.findByText(t.blockedUsers); + expect(blockedUsersBtn).toBeInTheDocument(); + + userEvent.click(blockedUsersBtn); + await waitFor(() => { + expect(screen.getByTestId('blockuser')).toBeInTheDocument(); + }); +}); + +it('Click Requests Card', async () => { + vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' }); + renderOrganizationDashboard(link1); + const requestsBtn = await screen.findByText(t.requests); + expect(requestsBtn).toBeInTheDocument(); + + userEvent.click(requestsBtn); + await waitFor(() => { + expect(screen.getByTestId('requests')).toBeInTheDocument(); + }); +}); + +it('Click View All Events', async () => { + vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' }); + renderOrganizationDashboard(link1); + const viewAllBtn = await screen.findAllByText(t.viewAll); + expect(viewAllBtn[0]).toBeInTheDocument(); + + userEvent.click(viewAllBtn[0]); + await waitFor(() => { + expect(screen.getByTestId('orgevents')).toBeInTheDocument(); + }); +}); + +it('Click View All Posts', async () => { + vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' }); + renderOrganizationDashboard(link1); + const viewAllBtn = await screen.findAllByText(t.viewAll); + expect(viewAllBtn[1]).toBeInTheDocument(); + + userEvent.click(viewAllBtn[1]); + await waitFor(() => { + expect(screen.getByTestId('orgpost')).toBeInTheDocument(); + }); +}); + +it('Click View All Requests', async () => { + vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' }); + renderOrganizationDashboard(link1); + const viewAllBtn = await screen.findAllByText(t.viewAll); + expect(viewAllBtn[2]).toBeInTheDocument(); + + userEvent.click(viewAllBtn[2]); + await waitFor(() => { + expect(toast.success).toHaveBeenCalled(); + }); +}); + +it('Click View All Leaderboard', async () => { + vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' }); + renderOrganizationDashboard(link1); + const viewAllBtn = await screen.findAllByText(t.viewAll); + expect(viewAllBtn[3]).toBeInTheDocument(); + + userEvent.click(viewAllBtn[3]); + await waitFor(() => { + expect(screen.getByTestId('leaderboard')).toBeInTheDocument(); + }); +}); + +it('should render Organization Dashboard screen with empty data', async () => { + vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' }); + renderOrganizationDashboard(link3); + + await waitFor(() => { + expect(screen.getByText(t.noUpcomingEvents)).toBeInTheDocument(); + expect(screen.getByText(t.noPostsPresent)).toBeInTheDocument(); + expect(screen.getByText(t.noMembershipRequests)).toBeInTheDocument(); + expect(screen.getByText(t.noVolunteers)).toBeInTheDocument(); + }); +}); + +it('should redirectt to / if error occurs', async () => { + vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' }); + renderOrganizationDashboard(link2); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalled(); + expect(screen.getByTestId('paramsError')).toBeInTheDocument(); + }); +}); diff --git a/src/screens/OrganizationDashboard/OrganizationDashboard.test.tsx b/src/screens/OrganizationDashboard/OrganizationDashboard.test.tsx deleted file mode 100644 index dde6b3120f..0000000000 --- a/src/screens/OrganizationDashboard/OrganizationDashboard.test.tsx +++ /dev/null @@ -1,202 +0,0 @@ -import { MockedProvider } from '@apollo/react-testing'; -import { fireEvent, 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 userEvent from '@testing-library/user-event'; -import { toast } from 'react-toastify'; -import { store } from 'state/store'; -import { StaticMockLink } from 'utils/StaticMockLink'; -import i18nForTest from 'utils/i18nForTest'; -import useLocalStorage from 'utils/useLocalstorage'; -import OrganizationDashboard from './OrganizationDashboard'; -import { EMPTY_MOCKS, ERROR_MOCKS, MOCKS } from './OrganizationDashboardMocks'; -import React, { act } from 'react'; -const { setItem } = useLocalStorage(); -import type { InterfaceQueryOrganizationEventListItem } from 'utils/interfaces'; - -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(EMPTY_MOCKS, true); -const link3 = new StaticMockLink(ERROR_MOCKS, true); - -jest.mock('react-toastify', () => ({ - toast: { - success: jest.fn(), - warn: jest.fn(), - error: jest.fn(), - }, -})); -const mockNavgate = jest.fn(); -let mockId: string | undefined = undefined; -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useNavigate: () => mockNavgate, - useParams: () => ({ orgId: mockId }), -})); - -beforeEach(() => { - setItem('FirstName', 'John'); - setItem('LastName', 'Doe'); - setItem( - 'UserImage', - 'https://api.dicebear.com/5.x/initials/svg?seed=John%20Doe', - ); -}); - -afterEach(() => { - jest.clearAllMocks(); - localStorage.clear(); -}); - -describe('Organisation Dashboard Page', () => { - test('Should render props and text elements test for the screen', async () => { - await act(async () => { - render( - - - - - - - - - , - ); - }); - - await wait(); - expect(screen.getByText('Members')).toBeInTheDocument(); - expect(screen.getByText('Admins')).toBeInTheDocument(); - expect(screen.getAllByText('Posts')).toHaveLength(1); - expect(screen.getAllByText('Events')).toHaveLength(1); - expect(screen.getByText('Blocked Users')).toBeInTheDocument(); - expect(screen.getByText('Requests')).toBeInTheDocument(); - expect(screen.getByText('Upcoming Events')).toBeInTheDocument(); - expect(screen.getByText('Latest Posts')).toBeInTheDocument(); - expect(screen.getByText('Membership requests')).toBeInTheDocument(); - - // Checking if posts are rendered - expect(screen.getByText('postone')).toBeInTheDocument(); - - // Checking if membership requests are rendered - expect(screen.getByText('Jane Doe')).toBeInTheDocument(); - - const peopleBtn = screen.getByText('Members'); - const adminBtn = screen.getByText('Admins'); - const postBtn = screen.getAllByText('Posts'); - const eventBtn = screen.getAllByText('Events'); - const blockUserBtn = screen.getByText('Blocked Users'); - const requestBtn = screen.getByText('Requests'); - userEvent.click(peopleBtn); - userEvent.click(adminBtn); - userEvent.click(postBtn[0]); - userEvent.click(eventBtn[0]); - userEvent.click(postBtn[0]); - userEvent.click(eventBtn[0]); - userEvent.click(blockUserBtn); - userEvent.click(requestBtn); - }); - - test('Testing buttons and checking empty events, posts and membership requests', async () => { - await act(async () => { - render( - - - - - - - - - , - ); - }); - - await wait(); - const viewEventsBtn = screen.getByTestId('viewAllEvents'); - const viewPostsBtn = screen.getByTestId('viewAllPosts'); - const viewMSBtn = screen.getByTestId('viewAllMembershipRequests'); - - userEvent.click(viewEventsBtn); - userEvent.click(viewPostsBtn); - fireEvent.click(viewMSBtn); - expect(toast.success).toBeCalledWith('Coming soon!'); - - expect( - screen.getByText(/No membership requests present/i), - ).toBeInTheDocument(); - expect(screen.getByText(/No upcoming events/i)).toBeInTheDocument(); - expect(screen.getByText(/No Posts Present/i)).toBeInTheDocument(); - }); - - test('Testing error scenario', async () => { - await act(async () => { - render( - - - - - - - - - , - ); - }); - - await wait(); - expect(mockNavgate).toHaveBeenCalledWith('/orglist'); - }); - test('upcomingEvents cardItem component should render when length>0', async () => { - mockId = '123'; - await act(async () => { - render( - - - - - - - - - , - ); - }); - screen.getByTestId('cardItem'); - }); - - test('event data should get updated using useState function', async () => { - mockId = '123'; - const mockSetState = jest.spyOn(React, 'useState'); - jest.doMock('react', () => ({ - ...jest.requireActual('react'), - useState: (initial: InterfaceQueryOrganizationEventListItem[]) => [ - initial, - mockSetState, - ], - })); - await act(async () => { - render( - - - - - - - - - , - ); - }); - expect(mockSetState).toHaveBeenCalled(); - }); -}); diff --git a/src/screens/OrganizationDashboard/OrganizationDashboard.tsx b/src/screens/OrganizationDashboard/OrganizationDashboard.tsx index 6927e4f874..abc712289c 100644 --- a/src/screens/OrganizationDashboard/OrganizationDashboard.tsx +++ b/src/screens/OrganizationDashboard/OrganizationDashboard.tsx @@ -1,5 +1,5 @@ import { useQuery } from '@apollo/client'; -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useMemo, useState } from 'react'; import { Button, Card } from 'react-bootstrap'; import Col from 'react-bootstrap/Col'; import Row from 'react-bootstrap/Row'; @@ -20,14 +20,19 @@ import CardItem from 'components/OrganizationDashCards/CardItem'; import CardItemLoading from 'components/OrganizationDashCards/CardItemLoading'; import DashBoardCard from 'components/OrganizationDashCards/DashboardCard'; import DashboardCardLoading from 'components/OrganizationDashCards/DashboardCardLoading'; -import { useNavigate, useParams } from 'react-router-dom'; +import { Navigate, useNavigate, useParams } from 'react-router-dom'; +import gold from 'assets/images/gold.png'; +import silver from 'assets/images/silver.png'; +import bronze from 'assets/images/bronze.png'; import { toast } from 'react-toastify'; import type { InterfaceQueryOrganizationEventListItem, InterfaceQueryOrganizationPostListItem, InterfaceQueryOrganizationsListObject, + InterfaceVolunteerRank, } from 'utils/interfaces'; -import styles from './OrganizationDashboard.module.css'; +import styles from 'style/app.module.css'; +import { VOLUNTEER_RANKING } from 'GraphQl/Queries/EventVolunteerQueries'; /** * Component for displaying the organization dashboard. @@ -36,15 +41,22 @@ import styles from './OrganizationDashboard.module.css'; * * @returns The rendered component. */ -function organizationDashboard(): JSX.Element { +function OrganizationDashboard(): JSX.Element { const { t } = useTranslation('translation', { keyPrefix: 'dashboard' }); const { t: tCommon } = useTranslation('common'); + const { t: tErrors } = useTranslation('errors'); document.title = t('title'); - const { orgId: currentUrl } = useParams(); - const peopleLink = `/orgpeople/${currentUrl}`; - const postsLink = `/orgpost/${currentUrl}`; - const eventsLink = `/orgevents/${currentUrl}`; - const blockUserLink = `/blockuser/${currentUrl}`; + const { orgId } = useParams(); + + if (!orgId) { + return ; + } + + const leaderboardLink = `/leaderboard/${orgId}`; + const peopleLink = `/orgpeople/${orgId}`; + const postsLink = `/orgpost/${orgId}`; + const eventsLink = `/orgevents/${orgId}`; + const blockUserLink = `/blockuser/${orgId}`; const requestLink = '/requests'; const navigate = useNavigate(); @@ -66,9 +78,38 @@ function organizationDashboard(): JSX.Element { loading: boolean; error?: ApolloError; } = useQuery(ORGANIZATIONS_LIST, { - variables: { id: currentUrl }, + variables: { id: orgId }, + }); + + /** + * Query to fetch vvolunteer rankings. + */ + const { + data: rankingsData, + loading: rankingsLoading, + error: errorRankings, + }: { + data?: { + getVolunteerRanks: InterfaceVolunteerRank[]; + }; + loading: boolean; + error?: ApolloError; + } = useQuery(VOLUNTEER_RANKING, { + variables: { + orgId, + where: { + orderBy: 'hours_DESC', + timeFrame: 'allTime', + limit: 3, + }, + }, }); + const rankings = useMemo( + () => rankingsData?.getVolunteerRanks || [], + [rankingsData], + ); + /** * Query to fetch posts for the organization. */ @@ -83,7 +124,7 @@ function organizationDashboard(): JSX.Element { loading: boolean; error?: ApolloError; } = useQuery(ORGANIZATION_POST_LIST, { - variables: { id: currentUrl, first: 10 }, + variables: { id: orgId, first: 10 }, }); /** @@ -95,7 +136,7 @@ function organizationDashboard(): JSX.Element { error: errorEvent, } = useQuery(ORGANIZATION_EVENT_CONNECTION_LIST, { variables: { - organization_id: currentUrl, + organization_id: orgId, }, }); @@ -122,11 +163,11 @@ function organizationDashboard(): JSX.Element { * UseEffect to handle errors and navigate if necessary. */ useEffect(() => { - if (errorOrg || errorPost || errorEvent) { - console.log('error', errorPost?.message); - navigate('/orglist'); + if (errorOrg || errorPost || errorEvent || errorRankings) { + toast.error(tErrors('errorLoading', { entity: '' })); + navigate('/'); } - }, [errorOrg, errorPost, errorEvent]); + }, [errorOrg, errorPost, errorEvent, errorRankings]); return ( <> @@ -136,7 +177,12 @@ function organizationDashboard(): JSX.Element { {[...Array(6)].map((_, index) => { return ( - + ); @@ -164,9 +210,12 @@ function organizationDashboard(): JSX.Element { sm={4} role="button" className="mb-4" - onClick={(): void => { - navigate(peopleLink); - }} + onClick={ + /*istanbul ignore next*/ + (): void => { + navigate(peopleLink); + } + } >
- + {loadingEvent ? ( [...Array(4)].map((_, index) => { - return ; + return ; }) ) : upcomingEvents.length == 0 ? (
@@ -292,10 +341,10 @@ function organizationDashboard(): JSX.Element { {t('viewAll')}
- + {loadingPost ? ( [...Array(4)].map((_, index) => { - return ; + return ; }) ) : postData?.organizations[0].posts.totalCount == 0 ? ( /* eslint-disable */ @@ -325,48 +374,116 @@ function organizationDashboard(): JSX.Element { - -
-
{t('membershipRequests')}
- -
- - {loadingOrgData ? ( - [...Array(4)].map((_, index) => { - return ; - }) - ) : data?.organizations[0].membershipRequests.length == 0 ? ( -
-
{t('noMembershipRequests')}
+ + +
+
+ {t('membershipRequests')}
- ) : ( - data?.organizations[0]?.membershipRequests - .slice(0, 8) - .map((request) => { + +
+ + {loadingOrgData ? ( + [...Array(4)].map((_, index) => { + return ; + }) + ) : data?.organizations[0].membershipRequests.length == 0 ? ( +
+
{t('noMembershipRequests')}
+
+ ) : ( + data?.organizations[0]?.membershipRequests + .slice(0, 8) + .map((request) => { + return ( + + ); + }) + )} +
+
+
+ + +
+
{t('volunteerRankings')}
+ +
+ + {rankingsLoading ? ( + [...Array(3)].map((_, index) => { + return ; + }) + ) : rankings.length == 0 ? ( +
+
{t('noVolunteers')}
+
+ ) : ( + rankings.map(({ rank, user, hoursVolunteered }, index) => { return ( - +
+
+
+ {rank <= 3 ? ( + gold + ) : ( + rank + )} +
+
{`${user.firstName} ${user.lastName}`}
+
- {hoursVolunteered} hours
+
+ {index < 2 &&
} +
); }) - )} -
-
+ )} + + +
); } -export default organizationDashboard; +export default OrganizationDashboard; diff --git a/src/screens/OrganizationDashboard/OrganizationDashboardMocks.ts b/src/screens/OrganizationDashboard/OrganizationDashboardMocks.ts index 26e5441f92..af1e9a799b 100644 --- a/src/screens/OrganizationDashboard/OrganizationDashboardMocks.ts +++ b/src/screens/OrganizationDashboard/OrganizationDashboardMocks.ts @@ -1,3 +1,4 @@ +import { VOLUNTEER_RANKING } from 'GraphQl/Queries/EventVolunteerQueries'; import { ORGANIZATIONS_LIST, ORGANIZATION_EVENT_CONNECTION_LIST, @@ -8,12 +9,13 @@ export const MOCKS = [ { request: { query: ORGANIZATIONS_LIST, + variables: { id: 'orgId' }, }, result: { data: { organizations: [ { - _id: 123, + _id: 'orgId', image: '', name: 'Dummy Organization', description: 'This is a Dummy Organization', @@ -53,7 +55,7 @@ export const MOCKS = [ ], membershipRequests: [ { - _id: '456', + _id: 'requestId1', user: { firstName: 'Jane', lastName: 'Doe', @@ -77,7 +79,7 @@ export const MOCKS = [ { request: { query: ORGANIZATION_POST_LIST, - variables: { first: 10 }, + variables: { id: 'orgId', first: 10 }, }, result: { data: { @@ -87,7 +89,7 @@ export const MOCKS = [ edges: [ { node: { - _id: '6411e53835d7ba2344a78e21', + _id: 'postId1', title: 'postone', text: 'This is the first post', imageUrl: null, @@ -105,11 +107,11 @@ export const MOCKS = [ pinned: true, likedBy: [], }, - cursor: '6411e53835d7ba2344a78e21', + cursor: 'postId1', }, { node: { - _id: '6411e54835d7ba2344a78e29', + _id: 'postId2', title: 'posttwo', text: 'Tis is the post two', imageUrl: null, @@ -127,11 +129,11 @@ export const MOCKS = [ likedBy: [], comments: [], }, - cursor: '6411e54835d7ba2344a78e29', + cursor: 'postId2', }, { node: { - _id: '6411e54835d7ba2344a78e30', + _id: 'postId3', title: 'posttwo', text: 'Tis is the post two', imageUrl: null, @@ -149,11 +151,11 @@ export const MOCKS = [ likedBy: [], comments: [], }, - cursor: '6411e54835d7ba2344a78e30', + cursor: 'postId3', }, { node: { - _id: '6411e54835d7ba2344a78e31', + _id: 'postId4', title: 'posttwo', text: 'Tis is the post two', imageUrl: null, @@ -171,12 +173,12 @@ export const MOCKS = [ likedBy: [], comments: [], }, - cursor: '6411e54835d7ba2344a78e31', + cursor: 'postId4', }, ], pageInfo: { - startCursor: '6411e53835d7ba2344a78e21', - endCursor: '6411e54835d7ba2344a78e31', + startCursor: 'postId1', + endCursor: 'postId4', hasNextPage: false, hasPreviousPage: false, }, @@ -191,15 +193,15 @@ export const MOCKS = [ request: { query: ORGANIZATION_EVENT_CONNECTION_LIST, variables: { - organization_id: '123', + organization_id: 'orgId', }, }, result: { data: { eventsByOrganizationConnection: [ { - _id: '1', - title: 'Sample Event', + _id: 'eventId1', + title: 'Event 1', description: 'Sample Description', startDate: '2025-10-29T00:00:00.000Z', endDate: '2023-10-29T23:59:59.000Z', @@ -208,14 +210,27 @@ export const MOCKS = [ endTime: '17:00:00', allDay: false, recurring: false, + attendees: [ + { + _id: 'userId1', + createdAt: '2023-01-01T00:00:00.000Z', + firstName: 'John', + lastName: 'Doe', + gender: 'Male', + eventsAttended: { + _id: 'eventId1', + endDate: '2023-10-29T23:59:59.000Z', + }, + }, + ], recurrenceRule: null, isRecurringEventException: false, isPublic: true, isRegisterable: true, }, { - _id: '2', - title: 'Sample Event', + _id: 'eventId2', + title: 'Event 2', description: 'Sample Description', startDate: '2022-10-29T00:00:00.000Z', endDate: '2023-10-29T23:59:59.000Z', @@ -223,6 +238,19 @@ export const MOCKS = [ startTime: '08:00:00', endTime: '17:00:00', allDay: false, + attendees: [ + { + _id: 'userId1', + createdAt: '2023-01-01T00:00:00.000Z', + firstName: 'John', + lastName: 'Doe', + gender: 'Male', + eventsAttended: { + _id: 'eventId1', + endDate: '2023-10-29T23:59:59.000Z', + }, + }, + ], recurring: false, recurrenceRule: null, isRecurringEventException: false, @@ -233,12 +261,76 @@ export const MOCKS = [ }, }, }, + { + request: { + query: VOLUNTEER_RANKING, + variables: { + orgId: 'orgId', + where: { + orderBy: 'hours_DESC', + timeFrame: 'allTime', + limit: 3, + }, + }, + }, + result: { + data: { + getVolunteerRanks: [ + { + rank: 1, + hoursVolunteered: 5, + user: { + _id: 'userId1', + lastName: 'Bradley', + firstName: 'Teresa', + image: null, + email: 'testuser4@example.com', + }, + }, + { + rank: 2, + hoursVolunteered: 4, + user: { + _id: 'userId2', + lastName: 'Garza', + firstName: 'Bruce', + image: null, + email: 'testuser5@example.com', + }, + }, + { + rank: 3, + hoursVolunteered: 3, + user: { + _id: 'userId3', + lastName: 'John', + firstName: 'Doe', + image: null, + email: 'testuser6@example.com', + }, + }, + { + rank: 4, + hoursVolunteered: 2, + user: { + _id: 'userId4', + lastName: 'Jane', + firstName: 'Doe', + image: null, + email: 'testuser7@example.com', + }, + }, + ], + }, + }, + }, ]; export const EMPTY_MOCKS = [ { request: { query: ORGANIZATIONS_LIST, + variables: { id: 'orgId' }, }, result: { data: { @@ -299,7 +391,7 @@ export const EMPTY_MOCKS = [ { request: { query: ORGANIZATION_POST_LIST, - variables: { first: 10 }, + variables: { id: 'orgId', first: 10 }, }, result: { data: { @@ -323,6 +415,9 @@ export const EMPTY_MOCKS = [ { request: { query: ORGANIZATION_EVENT_CONNECTION_LIST, + variables: { + organization_id: 'orgId', + }, }, result: { data: { @@ -330,25 +425,62 @@ export const EMPTY_MOCKS = [ }, }, }, + { + request: { + query: VOLUNTEER_RANKING, + variables: { + orgId: '123', + where: { + orderBy: 'hours_DESC', + timeFrame: 'allTime', + limit: 3, + }, + }, + }, + result: { + data: { + getVolunteerRanks: [], + }, + }, + }, ]; export const ERROR_MOCKS = [ { request: { query: ORGANIZATIONS_LIST, + variables: { id: 'orgId' }, }, error: new Error('Mock Graphql ORGANIZATIONS_LIST Error'), }, { request: { query: ORGANIZATION_POST_LIST, + variables: { id: 'orgId', first: 10 }, }, error: new Error('Mock Graphql ORGANIZATION_POST_LIST Error'), }, { request: { query: ORGANIZATION_EVENT_CONNECTION_LIST, + variables: { + organization_id: 'orgId', + }, }, error: new Error('Mock Graphql ORGANIZATION_EVENT_LIST Error'), }, + { + request: { + query: VOLUNTEER_RANKING, + variables: { + orgId: '123', + where: { + orderBy: 'hours_DESC', + timeFrame: 'allTime', + limit: 3, + }, + }, + }, + error: new Error('Mock Graphql VOLUNTEER_RANKING Error'), + }, ]; diff --git a/src/screens/OrganizationEvents/OrganizationEvents.module.css b/src/screens/OrganizationEvents/OrganizationEvents.module.css index 55e86fcaba..c26c074634 100644 --- a/src/screens/OrganizationEvents/OrganizationEvents.module.css +++ b/src/screens/OrganizationEvents/OrganizationEvents.module.css @@ -32,6 +32,7 @@ font-size: 19px; color: #707070; } + .mainpage { display: flex; flex-direction: row; @@ -60,7 +61,7 @@ font-size: 20px; margin-bottom: 30px; padding-bottom: 5px; - border-bottom: 3px solid #31bb6b; + border-bottom: 3px solid #eaebef; width: 15%; } @@ -71,13 +72,15 @@ margin-top: 50px; margin-bottom: 40px; padding-bottom: 5px; - border-bottom: 3px solid #31bb6b; + border-bottom: 3px solid #eaebef; width: 30%; } + .admindetails { display: flex; justify-content: space-between; } + .admindetails > p { margin-top: -12px; margin-right: 30px; @@ -111,6 +114,7 @@ transform 0.2s, box-shadow 0.2s; } + .flexdir { display: flex; flex-direction: row; @@ -141,33 +145,51 @@ justify-content: left; flex-direction: column; } + .logintitleinvite { color: #707070; font-weight: 600; font-size: 20px; margin-bottom: 20px; padding-bottom: 5px; - border-bottom: 3px solid #31bb6b; + border-bottom: 3px solid #eaebef; width: 40%; } + .titlemodal { color: #707070; font-weight: 600; font-size: 20px; margin-bottom: 20px; padding-bottom: 5px; - border-bottom: 3px solid #31bb6b; + border-bottom: 3px solid #eaebef; width: 65%; } + +.closeButton { + color: var(--delete-button-color); + margin-right: 5px; + background-color: var(--delete-button-bg); + border: white; +} + +.closeButton:hover { + color: var(--delete-button-bg) !important; + background-color: var(--delete-button-color) !important; + border: white; +} + .cancel > i { margin-top: 5px; transform: scale(1.2); cursor: pointer; color: #707070; } + .modalbody { width: 50px; } + .greenregbtn { margin: 1rem 0 0; margin-top: 15px; @@ -175,7 +197,7 @@ box-shadow: 0 2px 2px #e8e5e5; padding: 10px 10px; border-radius: 5px; - background-color: #31bb6b; + background-color: #eaebef; width: 100%; font-size: 16px; color: white; @@ -193,6 +215,7 @@ flex-direction: row; margin-bottom: 15px; } + .datebox { width: 90%; border-radius: 7px; @@ -206,18 +229,22 @@ margin-right: 5px; margin-left: 5px; } + .checkboxdiv > label { margin-right: 50px; } + .checkboxdiv > label > input { margin-left: 10px; } + .loader, .loader:after { border-radius: 50%; width: 10em; height: 10em; } + .loader { margin: 60px auto; margin-top: 35vh !important; @@ -234,40 +261,48 @@ -webkit-animation: load8 1.1s infinite linear; animation: load8 1.1s infinite linear; } + @-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); } } + .dispflex { display: flex; align-items: center; justify-content: space-between; } + .dispflex > input { border: none; box-shadow: none; margin-top: 5px; } + .checkboxdiv { display: flex; margin-bottom: 5px; } + .checkboxdiv > div { width: 50%; } @@ -322,6 +357,30 @@ padding: 7px 15px; } +.createButton { + background-color: #a8c7fa !important; + color: black !important; + margin: 1rem 0 0; + margin-top: 15px; + padding: 10px 10px; + border-radius: 5px; + font-size: 16px; + outline: none; + font-weight: 600; + cursor: pointer; + transition: + transform 0.2s, + box-shadow 0.2s; + width: 100%; + border: 1px solid var(--dropdown-border-color); +} + +.createButton:hover { + background-color: #286fe0 !important; + color: black !important; + border: 1px solid var(--dropdown-border-color) !important; +} + @media only screen and (max-width: 600px) { .form_wrapper { width: 90%; diff --git a/src/screens/OrganizationEvents/OrganizationEvents.test.tsx b/src/screens/OrganizationEvents/OrganizationEvents.test.tsx index 6c0491e2b2..09e896e031 100644 --- a/src/screens/OrganizationEvents/OrganizationEvents.test.tsx +++ b/src/screens/OrganizationEvents/OrganizationEvents.test.tsx @@ -282,7 +282,7 @@ describe('Organisation Events Page', () => { userEvent.click(screen.getByTestId('createEventBtn')); await waitFor(() => { - expect(toast.success).toBeCalledWith(translations.eventCreated); + expect(toast.success).toHaveBeenCalledWith(translations.eventCreated); }); await waitFor(() => { @@ -371,9 +371,9 @@ describe('Organisation Events Page', () => { expect(screen.getByTestId('registrableCheck')).toBeChecked(); userEvent.click(screen.getByTestId('createEventBtn')); - expect(toast.warning).toBeCalledWith('Title can not be blank!'); - expect(toast.warning).toBeCalledWith('Description can not be blank!'); - expect(toast.warning).toBeCalledWith('Location can not be blank!'); + expect(toast.warning).toHaveBeenCalledWith('Title can not be blank!'); + expect(toast.warning).toHaveBeenCalledWith('Description can not be blank!'); + expect(toast.warning).toHaveBeenCalledWith('Location can not be blank!'); userEvent.click(screen.getByTestId('createEventModalCloseBtn')); @@ -452,7 +452,7 @@ describe('Organisation Events Page', () => { userEvent.click(screen.getByTestId('createEventBtn')); await waitFor(() => { - expect(toast.success).toBeCalledWith(translations.eventCreated); + expect(toast.success).toHaveBeenCalledWith(translations.eventCreated); }); await waitFor(() => { diff --git a/src/screens/OrganizationEvents/OrganizationEvents.tsx b/src/screens/OrganizationEvents/OrganizationEvents.tsx index 4c90777c6e..71295c1dc9 100644 --- a/src/screens/OrganizationEvents/OrganizationEvents.tsx +++ b/src/screens/OrganizationEvents/OrganizationEvents.tsx @@ -71,6 +71,7 @@ function organizationEvents(): JSX.Element { const [publicchecked, setPublicChecked] = React.useState(true); const [registrablechecked, setRegistrableChecked] = React.useState(false); + const [createChatCheck, setCreateChatCheck] = React.useState(false); const [recurrenceRuleState, setRecurrenceRuleState] = useState({ @@ -285,6 +286,7 @@ function organizationEvents(): JSX.Element {
+
+
+ + setCreateChatCheck(!createChatCheck)} + /> +
+
{/* Recurrence Options */} {recurringchecked && ( @@ -490,7 +505,7 @@ function organizationEvents(): JSX.Element { -
+
@@ -426,7 +426,9 @@ const orgFundCampaign = (): JSX.Element => { ), }} sx={dataGridStyle} - getRowClassName={() => `${styles.rowBackground}`} + getRowClassName={() => + `${styles.rowBackgroundOrganizationFundCampaign}` + } autoHeight rowHeight={65} rows={campaigns.map((campaign, index) => ({ diff --git a/src/screens/OrganizationFundCampaign/OrganizationFundCampaign.module.css b/src/screens/OrganizationFundCampaign/OrganizationFundCampaign.module.css deleted file mode 100644 index 55202baef9..0000000000 --- a/src/screens/OrganizationFundCampaign/OrganizationFundCampaign.module.css +++ /dev/null @@ -1,202 +0,0 @@ -.organizationFundCampaignContainer { - margin: 0.5rem 0; -} -.goalButton { - border: 1px solid rgba(49, 187, 107, 1) !important; - color: rgba(49, 187, 107, 1) !important; - width: 75%; - padding: 10px; - border-radius: 8px; - display: block; - margin: auto; - box-shadow: 5px 5px 4px 0px rgba(49, 187, 107, 0.12); -} -.rowBackground { - background-color: var(--bs-white); - max-height: 120px; -} -.container { - min-height: 100vh; -} -.campaignModal { - max-width: 80vw; - margin-top: 2vh; - margin-left: 13vw; -} -.titlemodal { - color: #707070; - font-weight: 600; - 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; - 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%; - flex: 1; -} - -.redregbtn { - margin: 1rem 0 0; - margin-top: 15px; - border: 1px solid #e8e5e5; - box-shadow: 0 2px 2px #e8e5e5; - padding: 10px 10px; - border-radius: 5px; - width: 100%; - font-size: 16px; - color: white; - outline: none; - font-weight: 600; - cursor: pointer; - transition: - transform 0.2s, - box-shadow 0.2s; - width: 100%; - flex: 1; -} -.campaignNameInfo { - font-size: medium; - cursor: pointer; -} -.campaignNameInfo:hover { - color: blue; - transform: translateY(-2px); -} -.message { - margin-top: 25%; - display: flex; - justify-content: center; - align-items: center; - flex-direction: column; -} - -.inputField { - background-color: white; - box-shadow: 0 1px 1px #31bb6b; -} - -.dropdown { - background-color: white; - border: 1px solid #31bb6b; - position: relative; - display: inline-block; - color: #31bb6b; -} - -.btnsContainer { - display: flex; - margin: 2rem 0 2rem 0; - gap: 0.8rem; -} - -.btnsContainer .btnsBlock { - display: flex; - gap: 0.8rem; -} - -.btnsContainer .btnsBlock div button { - display: flex; - margin-left: 1rem; - justify-content: center; - align-items: center; -} - -.btnsContainer .input { - flex: 1; - position: relative; -} - -.btnsContainer input { - outline: 1px solid var(--bs-gray-400); -} - -.btnsContainer .input button { - width: 52px; -} - -.mainpageright > hr { - margin-top: 20px; - width: 100%; - margin-left: -15px; - margin-right: -15px; - margin-bottom: 20px; -} - -.tableHeader { - background-color: var(--bs-primary); - color: var(--bs-white); - font-size: 1rem; -} - -@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%; - } -} - -/* 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%; - } -} diff --git a/src/screens/OrganizationFunds/FundModal.test.tsx b/src/screens/OrganizationFunds/FundModal.spec.tsx similarity index 85% rename from src/screens/OrganizationFunds/FundModal.test.tsx rename to src/screens/OrganizationFunds/FundModal.spec.tsx index c74b0434c3..7296f31661 100644 --- a/src/screens/OrganizationFunds/FundModal.test.tsx +++ b/src/screens/OrganizationFunds/FundModal.spec.tsx @@ -21,11 +21,12 @@ import { toast } from 'react-toastify'; import { MOCKS, MOCKS_ERROR } from './OrganizationFundsMocks'; import type { InterfaceFundModal } from './FundModal'; import FundModal from './FundModal'; +import { vi } from 'vitest'; -jest.mock('react-toastify', () => ({ +vi.mock('react-toastify', () => ({ toast: { - success: jest.fn(), - error: jest.fn(), + success: vi.fn(), + error: vi.fn(), }, })); @@ -38,7 +39,7 @@ const translations = JSON.parse( const fundProps: InterfaceFundModal[] = [ { isOpen: true, - hide: jest.fn(), + hide: vi.fn(), fund: { _id: 'fundId', name: 'Fund 1', @@ -54,13 +55,13 @@ const fundProps: InterfaceFundModal[] = [ lastName: 'Doe', }, }, - refetchFunds: jest.fn(), + refetchFunds: vi.fn(), orgId: 'orgId', mode: 'create', }, { isOpen: true, - hide: jest.fn(), + hide: vi.fn(), fund: { _id: 'fundId', name: 'Fund 1', @@ -76,7 +77,7 @@ const fundProps: InterfaceFundModal[] = [ lastName: 'Doe', }, }, - refetchFunds: jest.fn(), + refetchFunds: vi.fn(), orgId: 'orgId', mode: 'edit', }, @@ -104,6 +105,7 @@ const renderFundModal = ( describe('PledgeModal', () => { afterEach(() => { cleanup(); + vi.clearAllMocks(); }); it('should populate form fields with correct values in edit mode', async () => { @@ -184,6 +186,37 @@ describe('PledgeModal', () => { }); }); + it('should not update the fund when no fields are changed', async () => { + renderFundModal(link1, fundProps[1]); + + // Simulate no change to the fields + const fundNameInput = screen.getByLabelText(translations.fundName); + fireEvent.change(fundNameInput, { target: { value: 'Fund 1' } }); + + const fundIdInput = screen.getByLabelText(translations.fundId); + fireEvent.change(fundIdInput, { target: { value: '1111' } }); + + const taxDeductibleSwitch = screen.getByTestId('setTaxDeductibleSwitch'); + fireEvent.click(taxDeductibleSwitch); + fireEvent.click(taxDeductibleSwitch); + + const defaultSwitch = screen.getByTestId('setDefaultSwitch'); + fireEvent.click(defaultSwitch); + fireEvent.click(defaultSwitch); + + const archivedSwitch = screen.getByTestId('archivedSwitch'); + fireEvent.click(archivedSwitch); + fireEvent.click(archivedSwitch); + + fireEvent.click(screen.getByTestId('createFundFormSubmitBtn')); + + await waitFor(() => { + expect(toast.success).not.toHaveBeenCalled(); + expect(fundProps[1].refetchFunds).not.toHaveBeenCalled(); + expect(fundProps[1].hide).not.toHaveBeenCalled(); + }); + }); + it('should update fund', async () => { renderFundModal(link1, fundProps[1]); diff --git a/src/screens/OrganizationFunds/FundModal.tsx b/src/screens/OrganizationFunds/FundModal.tsx index 0f112cba9b..b33270b30f 100644 --- a/src/screens/OrganizationFunds/FundModal.tsx +++ b/src/screens/OrganizationFunds/FundModal.tsx @@ -2,7 +2,7 @@ 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 styles from '../../style/app.module.css'; import { useTranslation } from 'react-i18next'; import { useMutation } from '@apollo/client'; import { @@ -139,7 +139,9 @@ const FundModal: React.FC = ({ if (isDefault != fund?.isDefault) { updatedFields.isDefault = isDefault; } - + if (Object.keys(updatedFields).length === 0) { + return; + } await updateFund({ variables: { id: fund?._id, @@ -157,9 +159,7 @@ const FundModal: React.FC = ({ hide(); toast.success(t('fundUpdated') as string); } catch (error: unknown) { - if (error instanceof Error) { - toast.error(error.message); - } + toast.error((error as Error).message); } }; @@ -173,7 +173,7 @@ const FundModal: React.FC = ({
} /> + } /> , ); + await waitFor(() => { + expect(window.location.pathname).toBe('/'); + }); await waitFor(() => { expect(screen.getByTestId('paramsError')).toBeInTheDocument(); }); }); it('open and close Create Fund modal', async () => { + vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' }); renderOrganizationFunds(link1); const createFundBtn = await screen.findByTestId('createFundBtn'); @@ -128,6 +135,7 @@ describe('OrganizationFunds Screen =>', () => { }); it('open and close update fund modal', async () => { + vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' }); renderOrganizationFunds(link1); await waitFor(() => { @@ -150,6 +158,7 @@ describe('OrganizationFunds Screen =>', () => { }); it('Search the Funds list by name', async () => { + vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' }); renderOrganizationFunds(link1); const searchField = await screen.findByTestId('searchByName'); fireEvent.change(searchField, { @@ -163,6 +172,7 @@ describe('OrganizationFunds Screen =>', () => { }); it('should render the Fund screen with error', async () => { + vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' }); renderOrganizationFunds(link2); await waitFor(() => { expect(screen.getByTestId('errorMsg')).toBeInTheDocument(); @@ -170,6 +180,7 @@ describe('OrganizationFunds Screen =>', () => { }); it('renders the empty fund component', async () => { + vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' }); renderOrganizationFunds(link3); await waitFor(() => expect(screen.getByText(translations.noFundsFound)).toBeInTheDocument(), @@ -177,6 +188,7 @@ describe('OrganizationFunds Screen =>', () => { }); it('Sort the Pledges list by Latest created Date', async () => { + vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' }); renderOrganizationFunds(link1); const sortBtn = await screen.findByTestId('filter'); @@ -198,6 +210,7 @@ describe('OrganizationFunds Screen =>', () => { }); it('Sort the Pledges list by Earliest created Date', async () => { + vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' }); renderOrganizationFunds(link1); const sortBtn = await screen.findByTestId('filter'); @@ -219,6 +232,7 @@ describe('OrganizationFunds Screen =>', () => { }); it('Click on Fund Name', async () => { + vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' }); renderOrganizationFunds(link1); const fundName = await screen.findAllByTestId('fundName'); @@ -231,6 +245,7 @@ describe('OrganizationFunds Screen =>', () => { }); it('Click on View Campaign', async () => { + vi.mocked(useParams).mockReturnValue({ orgId: 'orgId' }); renderOrganizationFunds(link1); const viewBtn = await screen.findAllByTestId('viewBtn'); diff --git a/src/screens/OrganizationFunds/OrganizationFunds.tsx b/src/screens/OrganizationFunds/OrganizationFunds.tsx index 29ffb0d865..ec9409fbe0 100644 --- a/src/screens/OrganizationFunds/OrganizationFunds.tsx +++ b/src/screens/OrganizationFunds/OrganizationFunds.tsx @@ -14,27 +14,30 @@ 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 styles from '../../style/app.module.css'; import type { InterfaceFundInfo } from 'utils/interfaces'; const dataGridStyle = { - '&.MuiDataGrid-root .MuiDataGrid-cell:focus-within': { - outline: 'none !important', - }, - '&.MuiDataGrid-root .MuiDataGrid-columnHeader:focus-within': { - outline: 'none', + borderRadius: '20px', + backgroundColor: '#EAEBEF', + '& .MuiDataGrid-row': { + backgroundColor: '#eff1f7', + '&:focus-within': { + outline: '2px solid #000', + outlineOffset: '-2px', + }, }, '& .MuiDataGrid-row:hover': { - backgroundColor: 'transparent', + backgroundColor: '#EAEBEF', + boxShadow: '0 0 0 1px rgba(0, 0, 0, 0.1)', }, '& .MuiDataGrid-row.Mui-hovered': { - backgroundColor: 'transparent', - }, - '& .MuiDataGrid-root': { - borderRadius: '0.5rem', + backgroundColor: '#EAEBEF', + boxShadow: '0 0 0 1px rgba(0, 0, 0, 0.1)', }, - '& .MuiDataGrid-main': { - borderRadius: '0.5rem', + '& .MuiDataGrid-cell:focus': { + outline: '2px solid #000', + outlineOffset: '-2px', }, }; @@ -157,7 +160,7 @@ const organizationFunds = (): JSX.Element => { minWidth: 100, align: 'center', headerAlign: 'center', - headerClassName: `${styles.tableHeader}`, + headerClassName: `${styles.tableHeaders}`, sortable: false, renderCell: (params: GridCellParams) => { return
{params.row.id}
; @@ -171,7 +174,7 @@ const organizationFunds = (): JSX.Element => { minWidth: 100, headerAlign: 'center', sortable: false, - headerClassName: `${styles.tableHeader}`, + headerClassName: `${styles.tableHeaders}`, renderCell: (params: GridCellParams) => { return (
{ minWidth: 100, headerAlign: 'center', sortable: false, - headerClassName: `${styles.tableHeader}`, + headerClassName: `${styles.tableHeaders}`, renderCell: (params: GridCellParams) => { return params.row.creator.firstName + ' ' + params.row.creator.lastName; }, @@ -204,7 +207,7 @@ const organizationFunds = (): JSX.Element => { minWidth: 100, headerAlign: 'center', sortable: false, - headerClassName: `${styles.tableHeader}`, + headerClassName: `${styles.tableHeaders}`, flex: 2, renderCell: (params: GridCellParams) => { return ( @@ -222,7 +225,7 @@ const organizationFunds = (): JSX.Element => { minWidth: 100, headerAlign: 'center', sortable: false, - headerClassName: `${styles.tableHeader}`, + headerClassName: `${styles.tableHeaders}`, renderCell: (params: GridCellParams) => { return params.row.isArchived ? 'Archived' : 'Active'; }, @@ -235,14 +238,15 @@ const organizationFunds = (): JSX.Element => { minWidth: 100, headerAlign: 'center', sortable: false, - headerClassName: `${styles.tableHeader}`, + headerClassName: `${styles.tableHeaders}`, renderCell: (params: GridCellParams) => { return ( <>
@@ -309,7 +312,7 @@ const organizationFunds = (): JSX.Element => { @@ -335,6 +338,7 @@ const organizationFunds = (): JSX.Element => {
@@ -413,7 +402,7 @@ function AddMember(): JSX.Element { + Add @@ -446,6 +437,7 @@ function AddMember(): JSX.Element { + {/* New User Modal */} @@ -559,7 +550,12 @@ function AddMember(): JSX.Element { variant="danger" onClick={closeCreateNewUserModal} data-testid="closeBtn" + style={{ + backgroundColor: 'var(--delete-button-bg)', + color: 'var(--delete-button-color)', + }} > + {translateOrgPeople('cancel')}
@@ -578,18 +579,3 @@ function AddMember(): JSX.Element { } export default AddMember; -// | typeof ORGANIZATIONS_MEMBER_CONNECTION_LIST -// | typeof ORGANIZATIONS_LIST -// | typeof USER_LIST_FOR_TABLE -// | typeof ADD_MEMBER_MUTATION; -// { -// id?: string; -// orgId?: string; -// orgid?: string; -// fristNameContains?: string; -// lastNameContains?: string; -// firstName_contains?: string; -// lastName_contains?: string; -// id_not_in?: string[]; -// userid?: string; -// }; diff --git a/src/screens/OrganizationPeople/OrganizationPeople.module.css b/src/screens/OrganizationPeople/OrganizationPeople.module.css deleted file mode 100644 index 5ff4b0d297..0000000000 --- a/src/screens/OrganizationPeople/OrganizationPeople.module.css +++ /dev/null @@ -1,121 +0,0 @@ -@media screen and (max-width: 575.5px) { - .mainpageright { - width: 98%; - } -} -.modalContent { - width: 670px; - max-width: 680px; -} -.dropdown { - background-color: white; - border: 1px solid #31bb6b; - position: relative; - display: inline-block; - margin-top: 10px; - margin-bottom: 10px; - color: #31bb6b; -} -.input { - flex: 1; - position: relative; -} - -.btnsContainer { - display: flex; - margin: 2.5rem 0 2.5rem 0; -} - -.btnsContainer .btnsBlock { - display: flex; -} - -.btnsContainer .btnsBlock button { - margin-left: 1rem; - display: flex; - justify-content: center; - align-items: center; -} - -.btnsContainer .input { - flex: 1; - position: relative; -} - -/* input { - outline: 1px solid var(--bs-gray-400); -} */ - -.btnsContainer .input button { - width: 52px; -} - -.inputField { - margin-top: 10px; - margin-bottom: 10px; - background-color: white; - box-shadow: 0 1px 1px #31bb6b; -} -.inputFieldModal { - margin-bottom: 10px; - background-color: white; - box-shadow: 0 1px 1px #31bb6b; -} -.inputField > 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; -} - -@-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/screens/OrganizationPeople/OrganizationPeople.test.tsx b/src/screens/OrganizationPeople/OrganizationPeople.spec.tsx similarity index 95% rename from src/screens/OrganizationPeople/OrganizationPeople.test.tsx rename to src/screens/OrganizationPeople/OrganizationPeople.spec.tsx index a840f1e1f0..1477c646f6 100644 --- a/src/screens/OrganizationPeople/OrganizationPeople.test.tsx +++ b/src/screens/OrganizationPeople/OrganizationPeople.spec.tsx @@ -2,6 +2,7 @@ import React, { act } from 'react'; import { MockedProvider } from '@apollo/react-testing'; import { fireEvent, render, screen } from '@testing-library/react'; import { Provider } from 'react-redux'; +import type { Params } from 'react-router-dom'; import { BrowserRouter } from 'react-router-dom'; import userEvent from '@testing-library/user-event'; import { I18nextProvider } from 'react-i18next'; @@ -13,7 +14,7 @@ import { USERS_CONNECTION_LIST, USER_LIST_FOR_TABLE, } from 'GraphQl/Queries/Queries'; -import 'jest-location-mock'; +// import 'jest-location-mock'; import i18nForTest from 'utils/i18nForTest'; import { StaticMockLink } from 'utils/StaticMockLink'; import { @@ -21,6 +22,29 @@ import { SIGNUP_MUTATION, } from 'GraphQl/Mutations/mutations'; import type { TestMock } from './MockDataTypes'; +import { vi } from 'vitest'; + +/** + * Mock window.location for testing redirection behavior. + */ + +Object.defineProperty(window, 'location', { + value: { + href: 'http://localhost/', + assign: vi.fn((url) => { + const urlObj = new URL(url, 'http://localhost'); + window.location.href = urlObj.href; + window.location.pathname = urlObj.pathname; + window.location.search = urlObj.search; + window.location.hash = urlObj.hash; + }), + reload: vi.fn(), + pathname: '/', + search: '', + hash: '', + origin: 'http://localhost', + }, +}); const createMemberMock = ( orgId = '', @@ -596,14 +620,18 @@ async function wait(ms = 2): Promise { }); } const linkURL = 'orgid'; -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useParams: () => ({ orgId: linkURL }), -})); + +vi.mock('react-router-dom', async () => { + const actualDom = await vi.importActual('react-router-dom'); + return { + ...actualDom, + useParams: (): Readonly> => ({ orgId: linkURL }), + }; +}); // TODO - REMOVE THE NEXT LINE IT IS TO SUPPRESS THE ERROR // FOR THE FIRST TEST WHICH CAME OUT OF NOWHERE -console.error = jest.fn(); +console.error = vi.fn(); describe('Organization People Page', () => { const searchData = { @@ -683,7 +711,7 @@ describe('Organization People Page', () => { }, ]); - expect(window.location).toBeAt('/orgpeople/orgid'); + expect(window.location.href).toBe('http://localhost/orgpeople/orgid'); }); test('It is necessary to query the correct mock data.', async () => { @@ -705,7 +733,7 @@ describe('Organization People Page', () => { await wait(); - expect(window.location).toBeAt('/orgpeople/orgid'); + expect(window.location.href).toBe('http://localhost/orgpeople/orgid'); }); test('Testing MEMBERS list', async () => { @@ -753,7 +781,7 @@ describe('Organization People Page', () => { ); await wait(); - expect(window.location).toBeAt('/orgpeople/orgid'); + expect(window.location.href).toBe('http://localhost/orgpeople/orgid'); }); test('Testing MEMBERS list with filters', async () => { @@ -792,7 +820,7 @@ describe('Organization People Page', () => { await wait(); expect(findtext).toBeInTheDocument(); await wait(); - expect(window.location).toBeAt('/orgpeople/orgid'); + expect(window.location.href).toBe('http://localhost/orgpeople/orgid'); }); test('Testing ADMIN LIST', async () => { @@ -855,7 +883,7 @@ describe('Organization People Page', () => { // Wait for any asynchronous operations to complete await wait(); - expect(window.location).toBeAt('/orgpeople/orgid'); + expect(window.location.href).toBe('http://localhost/orgpeople/orgid'); }); test('Testing ADMIN list with filters', async () => { @@ -905,7 +933,7 @@ describe('Organization People Page', () => { // Ensure that the name is still present after filtering await wait(); - expect(window.location).toBeAt('/orgpeople/orgid'); + expect(window.location.href).toBe('http://localhost/orgpeople/orgid'); }); test('Testing add existing user modal', async () => { @@ -1256,7 +1284,9 @@ describe('Organization People Page', () => { const btn = screen.getByTestId('searchbtn'); userEvent.click(btn); await wait(); - expect(window.location).toBeAt('/orgpeople/6401ff65ce8e8406b8f07af1'); + expect(window.location.href).toBe( + 'http://localhost/orgpeople/6401ff65ce8e8406b8f07af1', + ); }); test('Testing USERS list with filters', async () => { @@ -1289,7 +1319,9 @@ describe('Organization People Page', () => { const btn = screen.getByTestId('searchbtn'); userEvent.click(btn); await wait(); - expect(window.location).toBeAt('/orgpeople/6401ff65ce8e8406b8f07af2'); + expect(window.location.href).toBe( + 'http://localhost/orgpeople/6401ff65ce8e8406b8f07af2', + ); }); test('Add Member component renders', async () => { @@ -1378,7 +1410,7 @@ describe('Organization People Page', () => { ); await wait(); - expect(window.location).toBeAt('/orgpeople/orgid'); + expect(window.location.href).toBe('http://localhost/orgpeople/orgid'); expect(screen.queryByText(/Nothing Found !!/i)).toBeInTheDocument(); }); }); diff --git a/src/screens/OrganizationPeople/OrganizationPeople.tsx b/src/screens/OrganizationPeople/OrganizationPeople.tsx index 1d230ed058..47a2d2a3b2 100644 --- a/src/screens/OrganizationPeople/OrganizationPeople.tsx +++ b/src/screens/OrganizationPeople/OrganizationPeople.tsx @@ -1,5 +1,5 @@ import { useLazyQuery } from '@apollo/client'; -import { Search, Sort } from '@mui/icons-material'; +import { Delete, Search, Sort } from '@mui/icons-material'; import { ORGANIZATIONS_LIST, ORGANIZATIONS_MEMBER_CONNECTION_LIST, @@ -16,7 +16,7 @@ import { useTranslation } from 'react-i18next'; import { Link, useLocation, useParams } from 'react-router-dom'; import { toast } from 'react-toastify'; import AddMember from './AddMember'; -import styles from './OrganizationPeople.module.css'; +import styles from '../../style/app.module.css'; import { DataGrid } from '@mui/x-data-grid'; import type { GridColDef, GridCellParams } from '@mui/x-data-grid'; import { Stack } from '@mui/material'; @@ -214,7 +214,7 @@ function organizationPeople(): JSX.Element { {params.row?.firstName + ' ' + params.row?.lastName} @@ -258,15 +258,19 @@ function organizationPeople(): JSX.Element { ) : ( ); }, @@ -292,11 +296,10 @@ function organizationPeople(): JSX.Element { /> @@ -316,6 +319,7 @@ function organizationPeople(): JSX.Element { d-inline id="userslist" data-value="userslist" + className={styles.dropdownItem} data-name="displaylist" data-testid="users" defaultChecked={state == 2 ? true : false} @@ -331,6 +335,7 @@ function organizationPeople(): JSX.Element { d-inline id="memberslist" data-value="memberslist" + className={styles.dropdownItem} data-name="displaylist" data-testid="members" defaultChecked={state == 0 ? true : false} @@ -338,20 +343,25 @@ function organizationPeople(): JSX.Element { setState(0); }} > - + + {tCommon('members')} + { setState(1); }} > - + + {tCommon('admins')} + @@ -370,7 +380,6 @@ function organizationPeople(): JSX.Element { disableColumnMenu columnBufferPx={5} hideFooter={true} - className={`${styles.datagrid}`} getRowId={(row) => row._id} slots={{ noRowsOverlay: () => ( @@ -384,17 +393,26 @@ function organizationPeople(): JSX.Element { ), }} sx={{ - '&.MuiDataGrid-root .MuiDataGrid-cell:focus-within': { - outline: 'none !important', - }, - '&.MuiDataGrid-root .MuiDataGrid-columnHeader:focus-within': { - outline: 'none', + borderRadius: 'var(--table-head-radius)', + backgroundColor: 'var(--grey-bg-color)', + '& .MuiDataGrid-row': { + backgroundColor: 'var(--tablerow-bg-color)', + '&:focus-within': { + outline: '2px solid #000', + outlineOffset: '-2px', + }, }, '& .MuiDataGrid-row:hover': { - backgroundColor: 'transparent', + backgroundColor: 'var(--grey-bg-color)', + boxShadow: '0 0 0 1px rgba(0, 0, 0, 0.1)', }, '& .MuiDataGrid-row.Mui-hovered': { - backgroundColor: 'transparent', + backgroundColor: 'var(--grey-bg-color)', + boxShadow: '0 0 0 1px rgba(0, 0, 0, 0.1)', + }, + '& .MuiDataGrid-cell:focus': { + outline: '2px solid #000', + outlineOffset: '-2px', }, }} getRowClassName={() => `${styles.rowBackground}`} diff --git a/src/screens/OrganizationTags/OrganizationTags.module.css b/src/screens/OrganizationTags/OrganizationTags.module.css deleted file mode 100644 index 7251a79d0d..0000000000 --- a/src/screens/OrganizationTags/OrganizationTags.module.css +++ /dev/null @@ -1,141 +0,0 @@ -.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: 1120px) { - .contract { - padding-left: calc(250px + 2rem + 1.5rem); - } - - .listBox .itemCard { - width: 100%; - } -} - -@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; -} diff --git a/src/screens/OrganizationTags/OrganizationTags.test.tsx b/src/screens/OrganizationTags/OrganizationTags.test.tsx index 923a26d982..0d426d20ac 100644 --- a/src/screens/OrganizationTags/OrganizationTags.test.tsx +++ b/src/screens/OrganizationTags/OrganizationTags.test.tsx @@ -4,6 +4,7 @@ import type { RenderResult } from '@testing-library/react'; import { act, cleanup, + fireEvent, render, screen, waitFor, @@ -59,11 +60,11 @@ const renderOrganizationTags = (link: ApolloLink): RenderResult => { } /> } /> } /> @@ -87,7 +88,7 @@ describe('Organisation Tags Page', () => { cleanup(); }); - test('Component loads correctly', async () => { + test('component loads correctly', async () => { const { getByText } = renderOrganizationTags(link); await wait(); @@ -103,7 +104,7 @@ describe('Organisation Tags Page', () => { await wait(); await waitFor(() => { - expect(queryByText(translations.create)).not.toBeInTheDocument(); + expect(queryByText(translations.createTag)).not.toBeInTheDocument(); }); }); @@ -129,118 +130,170 @@ describe('Organisation Tags Page', () => { ); }); - test('opens and closes the remove tag modal', async () => { + test('navigates to sub tags screen after clicking on a tag', async () => { renderOrganizationTags(link); await wait(); await waitFor(() => { - expect(screen.getAllByTestId('removeUserTagBtn')[0]).toBeInTheDocument(); + expect(screen.getAllByTestId('tagName')[0]).toBeInTheDocument(); }); - userEvent.click(screen.getAllByTestId('removeUserTagBtn')[0]); + userEvent.click(screen.getAllByTestId('tagName')[0]); await waitFor(() => { - return expect( - screen.findByTestId('removeUserTagModalCloseBtn'), - ).resolves.toBeInTheDocument(); + expect(screen.getByTestId('subTagsScreen')).toBeInTheDocument(); }); - userEvent.click(screen.getByTestId('removeUserTagModalCloseBtn')); - - await waitForElementToBeRemoved(() => - screen.queryByTestId('removeUserTagModalCloseBtn'), - ); }); - test('navigates to sub tags screen after clicking on a tag', async () => { + test('navigates to manage tag page after clicking manage tag option', async () => { renderOrganizationTags(link); await wait(); await waitFor(() => { - expect(screen.getAllByTestId('tagName')[0]).toBeInTheDocument(); + expect(screen.getAllByTestId('manageTagBtn')[0]).toBeInTheDocument(); }); - userEvent.click(screen.getAllByTestId('tagName')[0]); + userEvent.click(screen.getAllByTestId('manageTagBtn')[0]); await waitFor(() => { - expect(screen.getByTestId('subTagsScreen')).toBeInTheDocument(); + expect(screen.getByTestId('manageTagScreen')).toBeInTheDocument(); }); }); - test('navigates to manage tag page after clicking manage tag option', async () => { + test('searchs for tags where the name matches the provided search input', async () => { renderOrganizationTags(link); await wait(); await waitFor(() => { - expect(screen.getAllByTestId('manageTagBtn')[0]).toBeInTheDocument(); + expect( + screen.getByPlaceholderText(translations.searchByName), + ).toBeInTheDocument(); }); - userEvent.click(screen.getAllByTestId('manageTagBtn')[0]); + const input = screen.getByPlaceholderText(translations.searchByName); + fireEvent.change(input, { target: { value: 'searchUserTag' } }); + // should render the two searched tags from the mock data + // where name starts with "searchUserTag" await waitFor(() => { - expect(screen.getByTestId('manageTagScreen')).toBeInTheDocument(); + const buttons = screen.getAllByTestId('manageTagBtn'); + expect(buttons.length).toEqual(2); }); }); - test('paginates between different pages', async () => { + test('fetches the tags by the sort order, i.e. latest or oldest first', async () => { renderOrganizationTags(link); await wait(); await waitFor(() => { - expect(screen.getByTestId('nextPagBtn')).toBeInTheDocument(); + expect( + screen.getByPlaceholderText(translations.searchByName), + ).toBeInTheDocument(); + }); + const input = screen.getByPlaceholderText(translations.searchByName); + fireEvent.change(input, { target: { value: 'searchUserTag' } }); + + // should render the two searched tags from the mock data + // where name starts with "searchUserTag" + await waitFor(() => { + expect(screen.getAllByTestId('tagName')[0]).toHaveTextContent( + 'searchUserTag 1', + ); + }); + + // now change the sorting order + await waitFor(() => { + expect(screen.getByTestId('sortTags')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('sortTags')); + + await waitFor(() => { + expect(screen.getByTestId('oldest')).toBeInTheDocument(); }); - userEvent.click(screen.getByTestId('nextPagBtn')); + userEvent.click(screen.getByTestId('oldest')); + // returns the tags in reverse order await waitFor(() => { - expect(screen.getAllByTestId('tagName')[0]).toHaveTextContent('6'); + expect(screen.getAllByTestId('tagName')[0]).toHaveTextContent( + 'searchUserTag 2', + ); }); await waitFor(() => { - expect(screen.getByTestId('previousPageBtn')).toBeInTheDocument(); + expect(screen.getByTestId('sortTags')).toBeInTheDocument(); }); - userEvent.click(screen.getByTestId('previousPageBtn')); + userEvent.click(screen.getByTestId('sortTags')); await waitFor(() => { - expect(screen.getAllByTestId('tagName')[0]).toHaveTextContent('1'); + expect(screen.getByTestId('latest')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('latest')); + + // reverse the order again + await waitFor(() => { + expect(screen.getAllByTestId('tagName')[0]).toHaveTextContent( + 'searchUserTag 1', + ); }); }); - test('creates a new user tag', async () => { - renderOrganizationTags(link); + test('fetches more tags with infinite scroll', async () => { + const { getByText } = renderOrganizationTags(link); await wait(); await waitFor(() => { - expect(screen.getByTestId('createTagBtn')).toBeInTheDocument(); + expect(getByText(translations.createTag)).toBeInTheDocument(); }); - userEvent.click(screen.getByTestId('createTagBtn')); - userEvent.type( - screen.getByPlaceholderText(translations.tagNamePlaceholder), - '7', + const orgUserTagsScrollableDiv = screen.getByTestId( + 'orgUserTagsScrollableDiv', ); - userEvent.click(screen.getByTestId('createTagSubmitBtn')); + // Get the initial number of tags loaded + const initialTagsDataLength = screen.getAllByTestId('manageTagBtn').length; + + // Set scroll position to the bottom + fireEvent.scroll(orgUserTagsScrollableDiv, { + target: { scrollY: orgUserTagsScrollableDiv.scrollHeight }, + }); await waitFor(() => { - expect(toast.success).toBeCalledWith(translations.tagCreationSuccess); + const finalTagsDataLength = screen.getAllByTestId('manageTagBtn').length; + expect(finalTagsDataLength).toBeGreaterThan(initialTagsDataLength); + + expect(getByText(translations.createTag)).toBeInTheDocument(); }); }); - test('removes a user tag', async () => { + test('creates a new user tag', async () => { renderOrganizationTags(link); await wait(); await waitFor(() => { - expect(screen.getAllByTestId('removeUserTagBtn')[0]).toBeInTheDocument(); + expect(screen.getByTestId('createTagBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('createTagBtn')); + + userEvent.click(screen.getByTestId('createTagSubmitBtn')); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalledWith(translations.enterTagName); }); - userEvent.click(screen.getAllByTestId('removeUserTagBtn')[0]); - userEvent.click(screen.getByTestId('removeUserTagSubmitBtn')); + userEvent.type( + screen.getByPlaceholderText(translations.tagNamePlaceholder), + 'userTag 12', + ); + + userEvent.click(screen.getByTestId('createTagSubmitBtn')); await waitFor(() => { - expect(toast.success).toBeCalledWith(translations.tagRemovalSuccess); + expect(toast.success).toHaveBeenCalledWith( + translations.tagCreationSuccess, + ); }); }); }); diff --git a/src/screens/OrganizationTags/OrganizationTags.tsx b/src/screens/OrganizationTags/OrganizationTags.tsx index e4bf0604e9..c88ca7b821 100644 --- a/src/screens/OrganizationTags/OrganizationTags.tsx +++ b/src/screens/OrganizationTags/OrganizationTags.tsx @@ -1,11 +1,10 @@ -import { useMutation, useQuery, type ApolloError } from '@apollo/client'; -import { Search, WarningAmberRounded } from '@mui/icons-material'; +import { useMutation, useQuery } from '@apollo/client'; +import { 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 React, { useEffect, useState } from 'react'; import { Form } from 'react-bootstrap'; import Button from 'react-bootstrap/Button'; import Dropdown from 'react-bootstrap/Dropdown'; @@ -13,17 +12,24 @@ 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 IconComponent from 'components/IconComponent/IconComponent'; +import type { + InterfaceQueryOrganizationUserTags, + InterfaceTagData, +} from 'utils/interfaces'; +import styles from '../../style/app.module.css'; import { DataGrid } from '@mui/x-data-grid'; -import { dataGridStyle } from 'utils/organizationTagsUtils'; +import type { + InterfaceOrganizationTagsQuery, + SortedByType, +} from 'utils/organizationTagsUtils'; +import { TAGS_QUERY_DATA_CHUNK_SIZE } 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'; +import { CREATE_USER_TAG } from 'GraphQl/Mutations/TagMutations'; +import InfiniteScroll from 'react-infinite-scroll-component'; +import InfiniteScrollLoader from 'components/InfiniteScrollLoader/InfiniteScrollLoader'; /** * Component that renders the Organization Tags screen when the app navigates to '/orgtags/:orgId'. @@ -40,19 +46,14 @@ function OrganizationTags(): JSX.Element { const [createTagModalIsOpen, setCreateTagModalIsOpen] = useState(false); + const [tagSearchName, setTagSearchName] = useState(''); + const [tagSortOrder, setTagSortOrder] = useState('DESCENDING'); + 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); @@ -67,29 +68,71 @@ function OrganizationTags(): JSX.Element { loading: orgUserTagsLoading, error: orgUserTagsError, refetch: orgUserTagsRefetch, - }: { - data?: { - organizations: InterfaceQueryOrganizationUserTags[]; - }; - loading: boolean; - error?: ApolloError; - refetch: () => void; - } = useQuery(ORGANIZATION_USER_TAGS_LIST, { + fetchMore: orgUserTagsFetchMore, + }: InterfaceOrganizationTagsQuery = useQuery(ORGANIZATION_USER_TAGS_LIST, { variables: { id: orgId, - after: after, - before: before, - first: first, - last: last, + first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { name: { starts_with: tagSearchName } }, + sortedBy: { id: tagSortOrder }, }, }); + const loadMoreUserTags = (): void => { + orgUserTagsFetchMore({ + variables: { + first: TAGS_QUERY_DATA_CHUNK_SIZE, + after: + orgUserTagsData?.organizations?.[0]?.userTags?.pageInfo?.endCursor ?? + /* istanbul ignore next */ + null, + }, + updateQuery: ( + prevResult: { organizations: InterfaceQueryOrganizationUserTags[] }, + { + fetchMoreResult, + }: { + fetchMoreResult?: { + organizations: InterfaceQueryOrganizationUserTags[]; + }; + }, + ) => { + if (!fetchMoreResult) /* istanbul ignore next */ return prevResult; + + return { + organizations: [ + { + ...prevResult.organizations[0], + userTags: { + ...prevResult.organizations[0].userTags, + edges: [ + ...prevResult.organizations[0].userTags.edges, + ...fetchMoreResult.organizations[0].userTags.edges, + ], + pageInfo: fetchMoreResult.organizations[0].userTags.pageInfo, + }, + }, + ], + }; + }, + }); + }; + + useEffect(() => { + orgUserTagsRefetch(); + }, []); + const [create, { loading: createUserTagLoading }] = useMutation(CREATE_USER_TAG); const createTag = async (e: ChangeEvent): Promise => { e.preventDefault(); + if (!tagName.trim()) { + toast.error(t('enterTagName')); + return; + } + try { const { data } = await create({ variables: { @@ -99,7 +142,7 @@ function OrganizationTags(): JSX.Element { }); if (data) { - toast.success(t('tagCreationSuccess') as string); + toast.success(t('tagCreationSuccess')); orgUserTagsRefetch(); setTagName(''); setCreateTagModalIsOpen(false); @@ -112,30 +155,6 @@ function OrganizationTags(): JSX.Element { } }; - 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 (
@@ -151,38 +170,18 @@ function OrganizationTags(): JSX.Element { ); } - 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}`); + 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', @@ -193,7 +192,7 @@ function OrganizationTags(): JSX.Element { headerClassName: `${styles.tableHeader}`, sortable: false, renderCell: (params: GridCellParams) => { - return
{tagSerialNumber * 5 + params.row.id}
; + return
{params.row.id}
; }, }, { @@ -203,16 +202,29 @@ function OrganizationTags(): JSX.Element { minWidth: 100, sortable: false, headerClassName: `${styles.tableHeader}`, - renderCell: (params: GridCellParams) => { + renderCell: (params: GridCellParams) => { return ( -
redirectToSubTags(params.row._id)} - > - {params.row.name} - - +
+ {params.row.parentTag && + params.row.ancestorTags?.map((tag) => ( +
+ {tag.name} + +
+ ))} + +
redirectToSubTags(params.row._id)} + > + {params.row.name} + +
); }, @@ -230,7 +242,7 @@ function OrganizationTags(): JSX.Element { return ( {params.row.childTags.totalCount} @@ -250,7 +262,7 @@ function OrganizationTags(): JSX.Element { return ( {params.row.usersAssignedTo.totalCount} @@ -268,28 +280,15 @@ function OrganizationTags(): JSX.Element { headerClassName: `${styles.tableHeader}`, renderCell: (params: GridCellParams) => { return ( -
- - - -
+ ); }, }, @@ -301,21 +300,16 @@ function OrganizationTags(): JSX.Element {
+ setTagSearchName(e.target.value.trim())} autoComplete="off" - required /> -
- {tCommon('sort')} + {tagSortOrder === 'DESCENDING' + ? tCommon('Latest') + : tCommon('Oldest')} - + setTagSortOrder('DESCENDING')} + > {tCommon('Latest')} - + setTagSortOrder('ASCENDING')} + > {tCommon('Oldest')}
- +
+ +
-
-
-
- + {orgUserTagsLoading || createUserTagLoading ? ( + + ) : ( +
+
+
+ +
+ +
+ {'Tags'} +
-
- {'Tags'} +
+ } + scrollableTarget="orgUserTagsScrollableDiv" + > + row.id} + slots={{ + noRowsOverlay: /* istanbul ignore next */ () => ( + + {t('noTagsFound')} + + ), + }} + sx={{ + borderRadius: '20px', + backgroundColor: '#EAEBEF', + '& .MuiDataGrid-row': { + backgroundColor: '#eff1f7', + '&:focus-within': { + // outline: '2px solid #000', + outlineOffset: '-2px', + }, + }, + '& .MuiDataGrid-row:hover': { + backgroundColor: '#EAEBEF', + boxShadow: '0 0 0 1px rgba(0, 0, 0, 0.1)', + }, + '& .MuiDataGrid-row.Mui-hovered': { + backgroundColor: '#EAEBEF', + boxShadow: '0 0 0 1px rgba(0, 0, 0, 0.1)', + }, + '& .MuiDataGrid-cell:focus': { + // outline: '2px solid #000', + outlineOffset: '-2px', + }, + }} + getRowClassName={() => `${styles.rowBackground}`} + autoHeight + rowHeight={65} + rows={userTagsList?.map((userTag, index) => ({ + id: index + 1, + ...userTag, + }))} + columns={columns} + isRowSelectable={() => false} + /> +
- 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} - /> -
-
- -
-
- -
-
- -
+ )}
@@ -429,11 +450,11 @@ function OrganizationTags(): JSX.Element { centered > - {t('tagDetails')} + {t('tagDetails')}
@@ -458,6 +479,7 @@ function OrganizationTags(): JSX.Element { variant="secondary" onClick={(): void => hideCreateTagModal()} data-testid="closeCreateTagModal" + className={styles.closeButton} > {tCommon('cancel')} @@ -465,49 +487,13 @@ function OrganizationTags(): JSX.Element { type="submit" value="invite" data-testid="createTagSubmitBtn" + className={styles.addButton} > {tCommon('create')} - - {/* Remove User Tag Modal */} - - - - {t('removeUserTag')} - - - {t('removeUserTagMessage')} - - - - - ); } diff --git a/src/screens/OrganizationTags/OrganizationTagsMocks.ts b/src/screens/OrganizationTags/OrganizationTagsMocks.ts index 3700c66c46..0fe48ca97f 100644 --- a/src/screens/OrganizationTags/OrganizationTagsMocks.ts +++ b/src/screens/OrganizationTags/OrganizationTagsMocks.ts @@ -1,8 +1,6 @@ -import { - CREATE_USER_TAG, - REMOVE_USER_TAG, -} from 'GraphQl/Mutations/TagMutations'; +import { CREATE_USER_TAG } from 'GraphQl/Mutations/TagMutations'; import { ORGANIZATION_USER_TAGS_LIST } from 'GraphQl/Queries/OrganizationQueries'; +import { TAGS_QUERY_DATA_CHUNK_SIZE } from 'utils/organizationTagsUtils'; export const MOCKS = [ { @@ -10,10 +8,9 @@ export const MOCKS = [ query: ORGANIZATION_USER_TAGS_LIST, variables: { id: '123', - after: null, - before: null, - first: 5, - last: null, + first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { name: { starts_with: '' } }, + sortedBy: { id: 'DESCENDING' }, }, }, result: { @@ -26,12 +23,14 @@ export const MOCKS = [ node: { _id: '1', name: 'userTag 1', + parentTag: null, usersAssignedTo: { totalCount: 5, }, childTags: { - totalCount: 5, + totalCount: 11, }, + ancestorTags: [], }, cursor: '1', }, @@ -39,12 +38,14 @@ export const MOCKS = [ node: { _id: '2', name: 'userTag 2', + parentTag: null, usersAssignedTo: { totalCount: 5, }, childTags: { totalCount: 0, }, + ancestorTags: [], }, cursor: '2', }, @@ -52,12 +53,14 @@ export const MOCKS = [ node: { _id: '3', name: 'userTag 3', + parentTag: null, usersAssignedTo: { totalCount: 0, }, childTags: { totalCount: 5, }, + ancestorTags: [], }, cursor: '3', }, @@ -65,12 +68,14 @@ export const MOCKS = [ node: { _id: '4', name: 'userTag 4', + parentTag: null, usersAssignedTo: { totalCount: 0, }, childTags: { totalCount: 0, }, + ancestorTags: [], }, cursor: '4', }, @@ -78,23 +83,100 @@ export const MOCKS = [ node: { _id: '5', name: 'userTag 5', + parentTag: null, usersAssignedTo: { totalCount: 5, }, childTags: { totalCount: 5, }, + ancestorTags: [], }, cursor: '5', }, + { + node: { + _id: '6', + name: 'userTag 6', + parentTag: null, + usersAssignedTo: { + totalCount: 6, + }, + childTags: { + totalCount: 6, + }, + ancestorTags: [], + }, + cursor: '6', + }, + { + node: { + _id: '7', + name: 'userTag 7', + parentTag: null, + usersAssignedTo: { + totalCount: 7, + }, + childTags: { + totalCount: 7, + }, + ancestorTags: [], + }, + cursor: '7', + }, + { + node: { + _id: '8', + name: 'userTag 8', + parentTag: null, + usersAssignedTo: { + totalCount: 8, + }, + childTags: { + totalCount: 8, + }, + ancestorTags: [], + }, + cursor: '8', + }, + { + node: { + _id: '9', + name: 'userTag 9', + parentTag: null, + usersAssignedTo: { + totalCount: 9, + }, + childTags: { + totalCount: 9, + }, + ancestorTags: [], + }, + cursor: '9', + }, + { + node: { + _id: '10', + name: 'userTag 10', + parentTag: null, + usersAssignedTo: { + totalCount: 10, + }, + childTags: { + totalCount: 10, + }, + ancestorTags: [], + }, + cursor: '10', + }, ], pageInfo: { startCursor: '1', - endCursor: '5', + endCursor: '10', hasNextPage: true, hasPreviousPage: false, }, - totalCount: 6, + totalCount: 12, }, }, ], @@ -106,10 +188,10 @@ export const MOCKS = [ query: ORGANIZATION_USER_TAGS_LIST, variables: { id: '123', - after: '5', - before: null, - first: 5, - last: null, + first: TAGS_QUERY_DATA_CHUNK_SIZE, + after: '10', + where: { name: { starts_with: '' } }, + sortedBy: { id: 'DESCENDING' }, }, }, result: { @@ -120,25 +202,42 @@ export const MOCKS = [ edges: [ { node: { - _id: '6', - name: 'userTag 6', + _id: '11', + name: 'userTag 11', + parentTag: null, usersAssignedTo: { - totalCount: 0, + totalCount: 5, + }, + childTags: { + totalCount: 5, + }, + ancestorTags: [], + }, + cursor: '11', + }, + { + node: { + _id: '12', + name: 'userTag 12', + parentTag: null, + usersAssignedTo: { + totalCount: 5, }, childTags: { totalCount: 0, }, + ancestorTags: [], }, - cursor: '6', + cursor: '12', }, ], pageInfo: { - startCursor: '6', - endCursor: '6', + startCursor: '11', + endCursor: '12', hasNextPage: false, hasPreviousPage: true, }, - totalCount: 6, + totalCount: 12, }, }, ], @@ -150,10 +249,9 @@ export const MOCKS = [ query: ORGANIZATION_USER_TAGS_LIST, variables: { id: '123', - after: null, - before: '6', - first: null, - last: 5, + first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { name: { starts_with: 'searchUserTag' } }, + sortedBy: { id: 'DESCENDING' }, }, }, result: { @@ -164,77 +262,130 @@ export const MOCKS = [ edges: [ { node: { - _id: '1', - name: 'userTag 1', + _id: 'searchUserTag1', + name: 'searchUserTag 1', + parentTag: { + _id: '1', + }, usersAssignedTo: { totalCount: 5, }, childTags: { totalCount: 5, }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], }, - cursor: '1', + cursor: 'searchUserTag1', }, { node: { - _id: '2', - name: 'userTag 2', + _id: 'searchUserTag2', + name: 'searchUserTag 2', + parentTag: { + _id: '1', + }, usersAssignedTo: { totalCount: 5, }, childTags: { totalCount: 0, }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], }, - cursor: '2', + cursor: 'searchUserTag2', }, + ], + pageInfo: { + startCursor: 'searchUserTag1', + endCursor: 'searchUserTag2', + hasNextPage: false, + hasPreviousPage: false, + }, + totalCount: 2, + }, + }, + ], + }, + }, + }, + { + request: { + query: ORGANIZATION_USER_TAGS_LIST, + variables: { + id: '123', + first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { name: { starts_with: 'searchUserTag' } }, + sortedBy: { id: 'ASCENDING' }, + }, + }, + result: { + data: { + organizations: [ + { + userTags: { + edges: [ { node: { - _id: '3', - name: 'userTag 3', + _id: 'searchUserTag2', + name: 'searchUserTag 2', + parentTag: { + _id: '1', + }, usersAssignedTo: { - totalCount: 0, + totalCount: 5, }, childTags: { totalCount: 5, }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], }, - cursor: '3', + cursor: 'searchUserTag2', }, { node: { - _id: '4', - name: 'userTag 4', - usersAssignedTo: { - totalCount: 0, - }, - childTags: { - totalCount: 0, + _id: 'searchUserTag1', + name: 'searchUserTag 1', + parentTag: { + _id: '1', }, - }, - cursor: '4', - }, - { - node: { - _id: '5', - name: 'userTag 5', usersAssignedTo: { totalCount: 5, }, childTags: { - totalCount: 5, + totalCount: 0, }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], }, - cursor: '5', + cursor: 'searchUserTag1', }, ], pageInfo: { - startCursor: '1', - endCursor: '5', - hasNextPage: true, + startCursor: 'searchUserTag2', + endCursor: 'searchUserTag1', + hasNextPage: false, hasPreviousPage: false, }, - totalCount: 6, + totalCount: 2, }, }, ], @@ -245,29 +396,14 @@ export const MOCKS = [ request: { query: CREATE_USER_TAG, variables: { - name: '7', + name: 'userTag 12', organizationId: '123', }, }, result: { data: { createUserTag: { - _id: '7', - }, - }, - }, - }, - { - request: { - query: REMOVE_USER_TAG, - variables: { - id: '1', - }, - }, - result: { - data: { - removeUserTag: { - _id: '1', + _id: '12', }, }, }, @@ -280,10 +416,9 @@ export const MOCKS_ERROR = [ query: ORGANIZATION_USER_TAGS_LIST, variables: { id: '123', - after: null, - before: null, - first: 5, - last: null, + first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { name: { starts_with: '' } }, + sortedBy: { id: 'DESCENDING' }, }, }, error: new Error('Mock Graphql Error'), diff --git a/src/screens/OrganizationVenues/OrganizationVenues.module.css b/src/screens/OrganizationVenues/OrganizationVenues.module.css deleted file mode 100644 index e4ac9d7575..0000000000 --- a/src/screens/OrganizationVenues/OrganizationVenues.module.css +++ /dev/null @@ -1,879 +0,0 @@ -.navbarbg { - height: 60px; - background-color: white; - display: flex; - margin-bottom: 30px; - z-index: 1; - position: relative; - flex-direction: row; - justify-content: space-between; - box-shadow: 0px 0px 8px 2px #c8c8c8; -} - -.logo { - color: #707070; - margin-left: 0; - display: flex; - align-items: center; - text-decoration: none; -} - -.logo img { - margin-top: 0px; - margin-left: 10px; - height: 64px; - width: 70px; -} - -.logo > strong { - line-height: 1.5rem; - margin-left: -5px; - font-family: sans-serif; - font-size: 19px; - color: #707070; -} -.mainpage { - display: flex; - flex-direction: row; -} - -.sidebar:after { - background-color: #f7f7f7; - position: absolute; - width: 2px; - height: 600px; - top: 10px; - left: 94%; - display: block; -} - -.navitem { - padding-left: 27%; - padding-top: 12px; - padding-bottom: 12px; - cursor: pointer; -} - -.logintitle { - color: #707070; - font-weight: 600; - font-size: 20px; - margin-bottom: 30px; - padding-bottom: 5px; - border-bottom: 3px solid #31bb6b; - width: 15%; -} - -.logintitleadmin { - color: #707070; - font-weight: 600; - font-size: 18px; - margin-top: 50px; - margin-bottom: 40px; - padding-bottom: 5px; - border-bottom: 3px solid #31bb6b; - width: 30%; -} -.admindetails { - display: flex; - justify-content: space-between; -} -.admindetails > p { - margin-top: -12px; - margin-right: 30px; -} - -.mainpageright > hr { - margin-top: 20px; - width: 100%; - margin-left: -15px; - margin-right: -15px; - margin-bottom: 20px; -} -.justifysp { - display: flex; - justify-content: space-between; - margin-top: 20px; -} - -.addbtn { - border: 1px solid #e8e5e5; - box-shadow: 0 2px 2px #e8e5e5; - border-radius: 5px; - font-size: 16px; - height: 60%; - color: white; - outline: none; - font-weight: 600; - cursor: pointer; - transition: - transform 0.2s, - box-shadow 0.2s; -} -.flexdir { - display: flex; - flex-direction: row; - justify-content: space-between; - border: none; -} - -.form_wrapper { - margin-top: 27px; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - position: absolute; - display: flex; - flex-direction: column; - padding: 40px 30px; - background: #ffffff; - border-color: #e8e5e5; - border-width: 5px; - border-radius: 10px; - max-height: 86vh; - overflow: auto; -} - -.form_wrapper form { - display: flex; - align-items: left; - justify-content: left; - flex-direction: column; -} -.logintitleinvite { - color: #707070; - font-weight: 600; - font-size: 20px; - margin-bottom: 20px; - padding-bottom: 5px; - border-bottom: 3px solid #31bb6b; - width: 40%; -} -.titlemodal { - color: #707070; - font-weight: 600; - font-size: 20px; - margin-bottom: 20px; - padding-bottom: 5px; - border-bottom: 3px solid #31bb6b; - width: 65%; -} -.cancel > i { - margin-top: 5px; - transform: scale(1.2); - cursor: pointer; - color: #707070; -} -.modalbody { - width: 50px; -} -.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%; -} - -.datediv { - display: flex; - flex-direction: row; - margin-bottom: 15px; -} -.datebox { - width: 90%; - border-radius: 7px; - border-color: #e8e5e5; - outline: none; - box-shadow: none; - padding-top: 2px; - padding-bottom: 2px; - padding-right: 5px; - padding-left: 5px; - margin-right: 5px; - margin-left: 5px; -} -.checkboxdiv > label { - margin-right: 50px; -} -.checkboxdiv > label > input { - margin-left: 10px; -} -.loader, -.loader:after { - border-radius: 50%; - width: 10em; - height: 10em; -} -.loader { - margin: 60px auto; - margin-top: 35vh !important; - font-size: 10px; - position: relative; - text-indent: -9999em; - border-top: 1.1em solid rgba(255, 255, 255, 0.2); - border-right: 1.1em solid rgba(255, 255, 255, 0.2); - border-bottom: 1.1em solid rgba(255, 255, 255, 0.2); - border-left: 1.1em solid #febc59; - -webkit-transform: translateZ(0); - -ms-transform: translateZ(0); - transform: translateZ(0); - -webkit-animation: load8 1.1s infinite linear; - animation: load8 1.1s infinite linear; -} -@-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); - } -} -.dispflex { - display: flex; - align-items: center; -} -.dispflex > input { - border: none; - box-shadow: none; - margin-top: 5px; -} -.checkboxdiv { - display: flex; -} -.checkboxdiv > div { - width: 50%; -} - -@media only screen and (max-width: 600px) { - .form_wrapper { - width: 90%; - top: 45%; - } -} - -.navbarbg { - height: 60px; - background-color: white; - display: flex; - margin-bottom: 30px; - z-index: 1; - position: relative; - flex-direction: row; - justify-content: space-between; - box-shadow: 0px 0px 8px 2px #c8c8c8; -} - -.logo { - color: #707070; - margin-left: 0; - display: flex; - align-items: center; - text-decoration: none; -} - -.logo img { - margin-top: 0px; - margin-left: 10px; - height: 64px; - width: 70px; -} - -.logo > strong { - line-height: 1.5rem; - margin-left: -5px; - font-family: sans-serif; - font-size: 19px; - color: #707070; -} -.mainpage { - display: flex; - flex-direction: row; -} -.sidebar { - display: flex; - width: 100%; - justify-content: space-between; - z-index: 0; - padding-top: 10px; - margin: 0; - height: 100%; -} - -.navitem { - padding-left: 27%; - padding-top: 12px; - padding-bottom: 12px; - cursor: pointer; -} - -.logintitle { - color: #707070; - font-weight: 600; - font-size: 20px; - margin-bottom: 30px; - padding-bottom: 5px; - border-bottom: 3px solid #31bb6b; - width: 15%; -} -.searchtitle { - color: #707070; - font-weight: 600; - font-size: 20px; - margin-bottom: 20px; - padding-bottom: 5px; - border-bottom: 3px solid #31bb6b; - width: 60%; -} -.justifysp { - display: flex; - justify-content: space-between; -} -@media screen and (max-width: 575.5px) { - .justifysp { - padding-left: 55px; - display: flex; - justify-content: space-between; - width: 100%; - } - .mainpageright { - width: 98%; - } -} - -.logintitleadmin { - color: #707070; - font-weight: 600; - font-size: 18px; - margin-top: 50px; - margin-bottom: 40px; - padding-bottom: 5px; - border-bottom: 3px solid #31bb6b; - width: 40%; -} -.admindetails { - display: flex; - justify-content: space-between; -} -.admindetails > p { - margin-top: -12px; - margin-right: 30px; -} -.mainpageright > hr { - margin-top: 10px; - width: 97%; - margin-left: -15px; - margin-right: -15px; - margin-bottom: 20px; -} -.addbtnmain { - width: 60%; - margin-right: 50px; -} -.addbtn { - float: right; - width: 23%; - border: 1px solid #e8e5e5; - box-shadow: 0 2px 2px #e8e5e5; - border-radius: 5px; - background-color: #31bb6b; - height: 40px; - font-size: 16px; - color: white; - outline: none; - font-weight: 600; - cursor: pointer; - margin-left: 30px; - transition: - transform 0.2s, - box-shadow 0.2s; -} -.flexdir { - display: flex; - flex-direction: row; - justify-content: space-between; - border: none; -} - -.form_wrapper { - margin-top: 27px; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - position: absolute; - display: flex; - flex-direction: column; - padding: 40px 30px; - background: #ffffff; - border-color: #e8e5e5; - border-width: 5px; - border-radius: 10px; -} - -.form_wrapper form { - display: flex; - align-items: left; - justify-content: left; - flex-direction: column; -} -.logintitleinvite { - color: #707070; - font-weight: 600; - font-size: 20px; - margin-bottom: 20px; - padding-bottom: 5px; - border-bottom: 3px solid #31bb6b; - width: 40%; -} -.cancel > i { - margin-top: 5px; - transform: scale(1.2); - cursor: pointer; - color: #707070; -} -.modalbody { - width: 50px; -} -.greenregbtn { - margin: 1rem 0 0; - margin-top: 10px; - 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%; -} -.dropdown { - background-color: white; - border: 1px solid #31bb6b; - position: relative; - display: inline-block; - margin-top: 10px; - margin-bottom: 10px; - color: #31bb6b; -} -.input { - flex: 1; - position: relative; -} -/* .btnsContainer { - display: flex; - margin: 2.5rem 0 2.5rem 0; - width: 100%; - flex-direction: row; - justify-content: space-between; - } */ - -.btnsContainer { - display: flex; - margin: 2.5rem 0 2.5rem 0; -} - -.btnsContainer .input { - flex: 1; - position: relative; - min-width: 18rem; - width: 25rem; -} - -.btnsContainer .input button { - width: 52px; -} -.searchBtn { - margin-bottom: 10px; -} - -.inputField { - margin-top: 10px; - margin-bottom: 10px; - background-color: white; - box-shadow: 0 1px 1px #31bb6b; -} -.inputField > button { - padding-top: 10px; - padding-bottom: 10px; -} -.TableImage { - background-color: #31bb6b !important; - width: 50px !important; - height: 50px !important; - border-radius: 100% !important; - margin-right: 10px !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; -} - -.loader, -.loader:after { - border-radius: 50%; - width: 10em; - height: 10em; -} -.loader { - margin: 60px auto; - margin-top: 35vh !important; - font-size: 10px; - position: relative; - text-indent: -9999em; - border-top: 1.1em solid rgba(255, 255, 255, 0.2); - border-right: 1.1em solid rgba(255, 255, 255, 0.2); - border-bottom: 1.1em solid rgba(255, 255, 255, 0.2); - border-left: 1.1em solid #febc59; - -webkit-transform: translateZ(0); - -ms-transform: translateZ(0); - transform: translateZ(0); - -webkit-animation: load8 1.1s infinite linear; - animation: load8 1.1s infinite linear; -} -.radio_buttons { - display: flex; - flex-direction: column; - gap: 0.5rem; - color: #707070; - font-weight: 600; - font-size: 14px; -} -.radio_buttons > input { - transform: scale(1.2); -} -.radio_buttons > label { - margin-top: -4px; - margin-left: 5px; - margin-right: 15px; -} -.preview { - display: flex; - position: relative; - width: 100%; - margin-top: 10px; - justify-content: center; -} -.preview img { - width: 400px; - height: auto; -} -.postimage { - border-radius: 0px; - width: 100%; - height: 12rem; - max-width: 100%; - max-height: 12rem; - object-fit: cover; - position: relative; - color: black; -} -.closeButtonP { - position: absolute; - top: 0px; - right: 0px; - background: transparent; - transform: scale(1.2); - cursor: pointer; - border: none; - color: #707070; - font-weight: 600; - font-size: 16px; - cursor: pointer; -} -.addbtn { - border: 1px solid #e8e5e5; - box-shadow: 0 2px 2px #e8e5e5; - border-radius: 5px; - font-size: 16px; - height: 60%; - color: white; - outline: none; - font-weight: 600; - cursor: pointer; - transition: - transform 0.2s, - box-shadow 0.2s; -} -@-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); - } -} -.list_box { - height: 65vh; - overflow-y: auto; - width: auto; -} - -.cards h2 { - font-size: 20px; -} -.cards > h3 { - font-size: 17px; -} -.card { - width: 100%; - height: 20rem; - margin-bottom: 2rem; -} -.postimage { - border-radius: 0px; - width: 100%; - height: 12rem; - max-width: 100%; - max-height: 12rem; - object-fit: cover; - position: relative; - color: black; -} -.preview { - display: flex; - position: relative; - width: 100%; - margin-top: 10px; - justify-content: center; -} -.preview img { - width: 400px; - height: auto; -} -.preview video { - width: 400px; - height: auto; -} -.novenueimage { - border-radius: 0px; - width: 100%; - height: 12rem; - max-height: 12rem; - object-fit: cover; - position: relative; -} -.cards:hover { - filter: brightness(0.8); -} -.cards:hover::before { - opacity: 0.5; -} -.knowMoreText { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - opacity: 0; - color: white; - padding: 10px; - font-weight: bold; - font-size: 1.5rem; - transition: opacity 0.3s ease-in-out; -} - -.cards:hover .knowMoreText { - opacity: 1; -} -.modal { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - display: flex; - align-items: center; - justify-content: center; - background-color: rgba( - 0, - 0, - 0, - 0.9 - ); /* Dark grey modal background with transparency */ - z-index: 9999; -} - -.modalContent { - display: flex; - align-items: center; - justify-content: center; - background-color: #fff; - padding: 20px; - max-width: 800px; - max-height: 600px; - overflow: auto; -} - -.modalImage { - flex: 1; - margin-right: 20px; - width: 25rem; - height: 15rem; -} -.nomodalImage { - flex: 1; - margin-right: 20px; - width: 100%; - height: 15rem; -} - -.modalImage img, -.modalImage video { - border-radius: 0px; - width: 100%; - height: 25rem; - max-width: 25rem; - max-height: 15rem; - object-fit: cover; - position: relative; -} -.modalInfo { - flex: 1; -} -.title { - font-size: 16px; - color: #000; - font-weight: 600; -} -.text { - font-size: 13px; - color: #000; - font-weight: 300; -} -.closeButton { - position: relative; - bottom: 5rem; - right: 10px; - padding: 4px; - background-color: red; /* Red close button color */ - color: #fff; - border: none; - cursor: pointer; -} -.closeButtonP { - position: absolute; - top: 0px; - right: 0px; - background: transparent; - transform: scale(1.2); - cursor: pointer; - border: none; - color: #707070; - font-weight: 600; - font-size: 16px; - cursor: pointer; -} -.cards:hover::after { - opacity: 1; - mix-blend-mode: normal; -} -.cards > p { - font-size: 14px; - margin-top: 0px; - margin-bottom: 7px; -} - -.cards:last-child:nth-last-child(odd) { - grid-column: auto / span 2; -} -.cards:first-child:nth-last-child(even), -.cards:first-child:nth-last-child(even) ~ .box { - grid-column: auto / span 1; -} - -.capacityLabel { - background-color: #31bb6b !important; - color: white; - height: 22.19px; - font-size: 12px; - font-weight: bolder; - padding: 0.1rem 0.3rem; - border-radius: 0.5rem; - position: relative; - overflow: hidden; -} - -.capacityLabel svg { - margin-bottom: 3px; -} - -::-webkit-scrollbar { - width: 20px; -} - -::-webkit-scrollbar-track { - background-color: transparent; -} - -::-webkit-scrollbar-thumb { - background-color: #d6dee1; -} - -::-webkit-scrollbar-thumb { - background-color: #d6dee1; - border-radius: 20px; -} - -::-webkit-scrollbar-thumb { - background-color: #d6dee1; - border-radius: 20px; - border: 6px solid transparent; - background-clip: content-box; -} diff --git a/src/screens/OrganizationVenues/OrganizationVenues.test.tsx b/src/screens/OrganizationVenues/OrganizationVenues.spec.tsx similarity index 92% rename from src/screens/OrganizationVenues/OrganizationVenues.test.tsx rename to src/screens/OrganizationVenues/OrganizationVenues.spec.tsx index 5b8b9933a1..e306c56cfc 100644 --- a/src/screens/OrganizationVenues/OrganizationVenues.test.tsx +++ b/src/screens/OrganizationVenues/OrganizationVenues.spec.tsx @@ -1,3 +1,15 @@ +/** + * Tests for the OrganizationVenues component. + * These tests include: + * - Ensuring the component renders correctly with default props. + * - Handling the absence of `orgId` by redirecting to the homepage. + * - Fetching and displaying venues via Apollo GraphQL queries. + * - Allowing users to search venues by name or description. + * - Sorting venues by capacity in ascending or descending order. + * - Verifying that long venue names or descriptions are handled gracefully. + * - Testing loading states and edge cases for Apollo queries. + * - Mocking GraphQL mutations for venue-related actions and validating their behavior. + */ import React from 'react'; import { MockedProvider } from '@apollo/react-testing'; import type { RenderResult } from '@testing-library/react'; @@ -10,7 +22,6 @@ import { } 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 OrganizationVenues from './OrganizationVenues'; import { store } from 'state/store'; @@ -19,7 +30,7 @@ import { StaticMockLink } from 'utils/StaticMockLink'; import { VENUE_LIST } from 'GraphQl/Queries/OrganizationQueries'; import type { ApolloLink } from '@apollo/client'; import { DELETE_VENUE_MUTATION } from 'GraphQl/Mutations/VenueMutations'; - +import { vi } from 'vitest'; const MOCKS = [ { request: { @@ -239,11 +250,11 @@ async function wait(ms = 100): Promise { }); } -jest.mock('react-toastify', () => ({ +vi.mock('react-toastify', () => ({ toast: { - success: jest.fn(), - warning: jest.fn(), - error: jest.fn(), + success: vi.fn(), + warning: vi.fn(), + error: vi.fn(), }, })); @@ -272,14 +283,14 @@ const renderOrganizationVenue = (link: ApolloLink): RenderResult => { describe('OrganizationVenue with missing orgId', () => { beforeAll(() => { - jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), + vi.doMock('react-router-dom', async () => ({ + ...(await vi.importActual('react-router-dom')), useParams: () => ({ orgId: undefined }), })); }); afterAll(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); }); test('Redirect to /orglist when orgId is falsy/undefined', async () => { render( @@ -299,7 +310,6 @@ describe('OrganizationVenue with missing orgId', () => { , ); - await waitFor(() => { const paramsError = screen.getByTestId('paramsError'); expect(paramsError).toBeInTheDocument(); @@ -308,17 +318,17 @@ describe('OrganizationVenue with missing orgId', () => { }); describe('Organisation Venues', () => { - global.alert = jest.fn(); + global.alert = vi.fn(); beforeAll(() => { - jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), + vi.doMock('react-router-dom', async () => ({ + ...(await vi.importActual('react-router-dom')), useParams: () => ({ orgId: 'orgId' }), })); }); afterAll(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); }); test('searches the venue list correctly by Name', async () => { diff --git a/src/screens/OrganizationVenues/OrganizationVenues.tsx b/src/screens/OrganizationVenues/OrganizationVenues.tsx index c2c3afe7e4..b3afda9685 100644 --- a/src/screens/OrganizationVenues/OrganizationVenues.tsx +++ b/src/screens/OrganizationVenues/OrganizationVenues.tsx @@ -1,7 +1,7 @@ import React, { useEffect, useState } from 'react'; import Button from 'react-bootstrap/Button'; import { useTranslation } from 'react-i18next'; -import styles from './OrganizationVenues.module.css'; +import styles from '../../style/app.module.css'; import { errorHandler } from 'utils/errorHandler'; import { useMutation, useQuery } from '@apollo/client'; import Col from 'react-bootstrap/Col'; @@ -147,7 +147,7 @@ function organizationVenues(): JSX.Element { -
-
+
} /> } /> @@ -99,19 +107,18 @@ const renderSubTags = (link: ApolloLink): RenderResult => { describe('Organisation Tags Page', () => { beforeEach(() => { - jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useParams: () => ({ orgId: 'orgId' }), + vi.mock('react-router-dom', async () => ({ + ...(await vi.importActual('react-router-dom')), })); cache.reset(); }); afterEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); cleanup(); }); - test('Component loads correctly', async () => { + it('Component loads correctly', async () => { const { getByText } = renderSubTags(link); await wait(); @@ -121,7 +128,7 @@ describe('Organisation Tags Page', () => { }); }); - test('render error component on unsuccessful subtags query', async () => { + it('render error component on unsuccessful subtags query', async () => { const { queryByText } = renderSubTags(link2); await wait(); @@ -131,17 +138,7 @@ describe('Organisation Tags Page', () => { }); }); - 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 () => { + it('opens and closes the create tag modal', async () => { renderSubTags(link); await wait(); @@ -163,29 +160,7 @@ describe('Organisation Tags Page', () => { ); }); - 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 () => { + it('navigates to manage tag screen after clicking manage tag option', async () => { renderSubTags(link); await wait(); @@ -200,7 +175,7 @@ describe('Organisation Tags Page', () => { }); }); - test('navigates to sub tags screen after clicking on a tag', async () => { + it('navigates to sub tags screen after clicking on a tag', async () => { renderSubTags(link); await wait(); @@ -215,7 +190,7 @@ describe('Organisation Tags Page', () => { }); }); - test('navigates to the different sub tag screen screen after clicking a tag in the breadcrumbs', async () => { + it('navigates to the different sub tag screen screen after clicking a tag in the breadcrumbs', async () => { renderSubTags(link); await wait(); @@ -230,7 +205,7 @@ describe('Organisation Tags Page', () => { }); }); - test('navigates to organization tags screen screen after clicking tha all tags option in the breadcrumbs', async () => { + it('navigates to organization tags screen screen after clicking tha all tags option in the breadcrumbs', async () => { renderSubTags(link); await wait(); @@ -245,7 +220,7 @@ describe('Organisation Tags Page', () => { }); }); - test('navigates to manage tags screen for the current tag after clicking tha manageCurrentTag button', async () => { + it('navigates to manage tags screen for the current tag after clicking tha manageCurrentTag button', async () => { renderSubTags(link); await wait(); @@ -260,66 +235,134 @@ describe('Organisation Tags Page', () => { }); }); - test('paginates between different pages', async () => { + it('searchs for tags where the name matches the provided search input', async () => { + renderSubTags(link); + + await wait(); + + await waitFor(() => { + expect( + screen.getByPlaceholderText(translations.searchByName), + ).toBeInTheDocument(); + }); + const input = screen.getByPlaceholderText(translations.searchByName); + fireEvent.change(input, { target: { value: 'searchSubTag' } }); + + // should render the two searched tags from the mock data + // where name starts with "searchUserTag" + await waitFor(() => { + const buttons = screen.getAllByTestId('manageTagBtn'); + expect(buttons.length).toEqual(2); + }); + }); + + it('fetches the tags by the sort order, i.e. latest or oldest first', async () => { renderSubTags(link); await wait(); await waitFor(() => { - expect(screen.getByTestId('nextPagBtn')).toBeInTheDocument(); + expect( + screen.getByPlaceholderText(translations.searchByName), + ).toBeInTheDocument(); + }); + const input = screen.getByPlaceholderText(translations.searchByName); + fireEvent.change(input, { target: { value: 'searchSubTag' } }); + + // should render the two searched tags from the mock data + // where name starts with "searchUserTag" + await waitFor(() => { + expect(screen.getAllByTestId('tagName')[0]).toHaveTextContent( + 'searchSubTag 1', + ); }); - userEvent.click(screen.getByTestId('nextPagBtn')); + // now change the sorting order await waitFor(() => { - expect(screen.getAllByTestId('tagName')[0]).toHaveTextContent('subTag 6'); + expect(screen.getByTestId('sortTags')).toBeInTheDocument(); }); + userEvent.click(screen.getByTestId('sortTags')); await waitFor(() => { - expect(screen.getByTestId('previousPageBtn')).toBeInTheDocument(); + expect(screen.getByTestId('oldest')).toBeInTheDocument(); }); - userEvent.click(screen.getByTestId('previousPageBtn')); + userEvent.click(screen.getByTestId('oldest')); + // returns the tags in reverse order await waitFor(() => { - expect(screen.getAllByTestId('tagName')[0]).toHaveTextContent('subTag 1'); + expect(screen.getAllByTestId('tagName')[0]).toHaveTextContent( + 'searchSubTag 2', + ); + }); + + await waitFor(() => { + expect(screen.getByTestId('sortTags')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('sortTags')); + + await waitFor(() => { + expect(screen.getByTestId('latest')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('latest')); + + // reverse the order again + await waitFor(() => { + expect(screen.getAllByTestId('tagName')[0]).toHaveTextContent( + 'searchSubTag 1', + ); }); }); - test('adds a new sub tag to the current tag', async () => { - renderSubTags(link); + it('Fetches more sub tags with infinite scroll', async () => { + const { getByText } = renderSubTags(link); await wait(); await waitFor(() => { - expect(screen.getByTestId('addSubTagBtn')).toBeInTheDocument(); + expect(getByText(translations.addChildTag)).toBeInTheDocument(); }); - userEvent.click(screen.getByTestId('addSubTagBtn')); - userEvent.type( - screen.getByPlaceholderText(translations.tagNamePlaceholder), - 'subTag 7', - ); + const subTagsScrollableDiv = screen.getByTestId('subTagsScrollableDiv'); - userEvent.click(screen.getByTestId('addSubTagSubmitBtn')); + // Get the initial number of tags loaded + const initialSubTagsDataLength = + screen.getAllByTestId('manageTagBtn').length; + + // Set scroll position to the bottom + fireEvent.scroll(subTagsScrollableDiv, { + target: { scrollY: subTagsScrollableDiv.scrollHeight }, + }); await waitFor(() => { - expect(toast.success).toBeCalledWith(translations.tagCreationSuccess); + const finalSubTagsDataLength = + screen.getAllByTestId('manageTagBtn').length; + expect(finalSubTagsDataLength).toBeGreaterThan(initialSubTagsDataLength); + + expect(getByText(translations.addChildTag)).toBeInTheDocument(); }); }); - test('removes a sub tag', async () => { + it('adds a new sub tag to the current tag', async () => { renderSubTags(link); await wait(); await waitFor(() => { - expect(screen.getAllByTestId('removeUserTagBtn')[0]).toBeInTheDocument(); + expect(screen.getByTestId('addSubTagBtn')).toBeInTheDocument(); }); - userEvent.click(screen.getAllByTestId('removeUserTagBtn')[0]); + userEvent.click(screen.getByTestId('addSubTagBtn')); + + userEvent.type( + screen.getByPlaceholderText(translations.tagNamePlaceholder), + 'subTag 12', + ); - userEvent.click(screen.getByTestId('removeUserTagSubmitBtn')); + userEvent.click(screen.getByTestId('addSubTagSubmitBtn')); await waitFor(() => { - expect(toast.success).toBeCalledWith(translations.tagRemovalSuccess); + expect(toast.success).toHaveBeenCalledWith( + translations.tagCreationSuccess, + ); }); }); }); diff --git a/src/screens/SubTags/SubTags.tsx b/src/screens/SubTags/SubTags.tsx index b381c9f816..6a20e875ec 100644 --- a/src/screens/SubTags/SubTags.tsx +++ b/src/screens/SubTags/SubTags.tsx @@ -1,4 +1,4 @@ -import { useMutation, useQuery, type ApolloError } from '@apollo/client'; +import { useMutation, useQuery } from '@apollo/client'; import { Search, WarningAmberRounded } from '@mui/icons-material'; import SortIcon from '@mui/icons-material/Sort'; import Loader from 'components/Loader/Loader'; @@ -14,19 +14,22 @@ 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 styles from '../../style/app.module.css'; import { DataGrid } from '@mui/x-data-grid'; -import { dataGridStyle } from 'utils/organizationTagsUtils'; +import type { + InterfaceOrganizationSubTagsQuery, + SortedByType, +} from 'utils/organizationTagsUtils'; +import { + dataGridStyle, + TAGS_QUERY_DATA_CHUNK_SIZE, +} 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'; +import { CREATE_USER_TAG } from 'GraphQl/Mutations/TagMutations'; +import { USER_TAG_SUB_TAGS } from 'GraphQl/Queries/userTagQueries'; +import InfiniteScroll from 'react-infinite-scroll-component'; +import InfiniteScrollLoader from 'components/InfiniteScrollLoader/InfiniteScrollLoader'; /** * Component that renders the SubTags screen when the app navigates to '/orgtags/:orgId/subtags/:tagId'. @@ -47,16 +50,10 @@ function SubTags(): JSX.Element { 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 [tagSearchName, setTagSearchName] = useState(''); + const [tagSortOrder, setTagSortOrder] = useState('DESCENDING'); const showAddSubTagModal = (): void => { setAddSubTagModalIsOpen(true); @@ -69,45 +66,51 @@ function SubTags(): JSX.Element { const { data: subTagsData, - loading: subTagsLoading, error: subTagsError, + loading: subTagsLoading, refetch: subTagsRefetch, - }: { - data?: { - getUserTag: InterfaceQueryUserTagChildTags; - }; - loading: boolean; - error?: ApolloError; - refetch: () => void; - } = useQuery(USER_TAG_SUB_TAGS, { + fetchMore: fetchMoreSubTags, + }: InterfaceOrganizationSubTagsQuery = useQuery(USER_TAG_SUB_TAGS, { variables: { id: parentTagId, - after: after, - before: before, - first: first, - last: last, + first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { name: { starts_with: tagSearchName } }, + sortedBy: { id: tagSortOrder }, }, }); - 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 loadMoreSubTags = (): void => { + fetchMoreSubTags({ + variables: { + first: TAGS_QUERY_DATA_CHUNK_SIZE, + after: subTagsData?.getChildTags.childTags.pageInfo.endCursor, + }, + updateQuery: ( + prevResult: { getChildTags: InterfaceQueryUserTagChildTags }, + { + fetchMoreResult, + }: { + fetchMoreResult?: { getChildTags: InterfaceQueryUserTagChildTags }; + }, + ) => { + /* istanbul ignore next -- @preserve */ + if (!fetchMoreResult) return prevResult; + + return { + getChildTags: { + ...fetchMoreResult.getChildTags, + childTags: { + ...fetchMoreResult.getChildTags.childTags, + edges: [ + ...prevResult.getChildTags.childTags.edges, + ...fetchMoreResult.getChildTags.childTags.edges, + ], + }, + }, + }; + }, + }); + }; const [create, { loading: createUserTagLoading }] = useMutation(CREATE_USER_TAG); @@ -124,7 +127,7 @@ function SubTags(): JSX.Element { }, }); - /* istanbul ignore next */ + /* istanbul ignore next -- @preserve */ if (data) { toast.success(t('tagCreationSuccess') as string); subTagsRefetch(); @@ -132,88 +135,48 @@ function SubTags(): JSX.Element { 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 */ + /* istanbul ignore next -- @preserve */ 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) { + if (subTagsError) { return (
- Error occured while loading{' '} - {subTagsError ? 'sub tags' : 'tag ancestors'} -
- {subTagsError - ? subTagsError.message - : orgUserTagsAncestorsError?.message} + Error occured while loading sub tags
); } - const userTagsList = subTagsData?.getUserTag.childTags.edges.map( - (edge) => edge.node, - ); + const subTagsList = + /* istanbul ignore next -- @preserve */ + subTagsData?.getChildTags.childTags.edges.map((edge) => edge.node) ?? []; + + const parentTagName = subTagsData?.getChildTags.name; - const orgUserTagAncestors = orgUserTagAncestorsData?.getUserTagAncestors; + // get the ancestorTags array and push the current tag in it + // used for the tag breadcrumbs + const orgUserTagAncestors = [ + ...(subTagsData?.getChildTags.ancestorTags ?? []), + { + _id: parentTagId, + name: parentTagName, + }, + ]; 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); + navigate(`/orgtags/${orgId}/subTags/${tagId}`); }; const columns: GridColDef[] = [ @@ -263,7 +226,7 @@ function SubTags(): JSX.Element { return ( {params.row.childTags.totalCount} @@ -283,7 +246,7 @@ function SubTags(): JSX.Element { return ( {params.row.usersAssignedTo.totalCount} @@ -301,28 +264,14 @@ function SubTags(): JSX.Element { headerClassName: `${styles.tableHeader}`, renderCell: (params: GridCellParams) => { return ( -
- - - -
+ ); }, }, @@ -330,153 +279,160 @@ function SubTags(): JSX.Element { return ( <> - -
-
-
+ +
+
+
setTagSearchName(e.target.value.trim())} data-testid="searchByName" autoComplete="off" - required />
-
- + {tCommon('Oldest')} + + + - + - -
+
-
-
-
- -
- -
navigate(`/orgtags/${orgId}`)} - className={`fs-6 ms-3 my-1 ${styles.tagsBreadCrumbs}`} - data-testid="allTagsBtn" - > - {'Tags'} - -
+ {subTagsLoading || createUserTagLoading ? ( + + ) : ( +
+
+
+ +
- {orgUserTagAncestors?.map((tag, index) => (
redirectToSubTags(tag._id as string)} - data-testid="redirectToSubTags" + onClick={() => navigate(`/orgtags/${orgId}`)} + className={`fs-6 ms-3 my-1 ${styles.tagsBreadCrumbs}`} + data-testid="allTagsBtn" > - {tag.name} - - {orgUserTagAncestors.length - 1 !== index && ( - - )} + {'Tags'} +
- ))} -
- row._id} - slots={{ - noRowsOverlay: /* istanbul ignore next */ () => ( - ( +
redirectToSubTags(tag._id as string)} + data-testid="redirectToSubTags" > - {t('noTagsFound')} - - ), - }} - sx={dataGridStyle} - getRowClassName={() => `${styles.rowBackground}`} - autoHeight - rowHeight={65} - rows={userTagsList?.map((fund, index) => ({ - id: index + 1, - ...fund, - }))} - columns={columns} - isRowSelectable={() => false} - /> -
-
+ {tag.name} -
-
- -
-
- -
+ {orgUserTagAncestors.length - 1 !== index && ( + + )} +
+ ))} +
+
+ } + scrollableTarget="subTagsScrollableDiv" + > + row.id} + slots={{ + noRowsOverlay: + /* istanbul ignore next -- @preserve */ () => ( + + {t('noTagsFound')} + + ), + }} + sx={dataGridStyle} + getRowClassName={() => `${styles.rowBackground}`} + autoHeight + rowHeight={65} + rows={subTagsList?.map((subTag, index) => ({ + id: index + 1, + ...subTag, + }))} + columns={columns} + isRowSelectable={() => false} + /> + +
+
+ )}
@@ -489,11 +445,11 @@ function SubTags(): JSX.Element { centered > - {t('tagDetails')} + {t('tagDetails')}
@@ -518,53 +474,21 @@ function SubTags(): JSX.Element { variant="secondary" onClick={(): void => hideAddSubTagModal()} data-testid="addSubTagModalCloseBtn" + className={styles.closeButton} > {tCommon('cancel')} - - - {/* Remove User Tag Modal */} - - - - {t('removeUserTag')} - - - {t('removeUserTagMessage')} - - - - - ); } diff --git a/src/screens/SubTags/SubTagsMocks.ts b/src/screens/SubTags/SubTagsMocks.ts index 757f3f42ad..5165ea3a53 100644 --- a/src/screens/SubTags/SubTagsMocks.ts +++ b/src/screens/SubTags/SubTagsMocks.ts @@ -1,33 +1,27 @@ -import { - CREATE_USER_TAG, - REMOVE_USER_TAG, -} from 'GraphQl/Mutations/TagMutations'; -import { - USER_TAG_ANCESTORS, - USER_TAG_SUB_TAGS, -} from 'GraphQl/Queries/userTagQueries'; +import { CREATE_USER_TAG } from 'GraphQl/Mutations/TagMutations'; +import { USER_TAG_SUB_TAGS } from 'GraphQl/Queries/userTagQueries'; +import { TAGS_QUERY_DATA_CHUNK_SIZE } from 'utils/organizationTagsUtils'; export const MOCKS = [ { request: { query: USER_TAG_SUB_TAGS, variables: { - id: 'tag1', - after: null, - before: null, - first: 5, - last: null, + id: '1', + first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { name: { starts_with: '' } }, + sortedBy: { id: 'DESCENDING' }, }, }, result: { data: { - getUserTag: { - name: 'tag1', + getChildTags: { + name: 'userTag 1', childTags: { edges: [ { node: { - _id: '1', + _id: 'subTag1', name: 'subTag 1', usersAssignedTo: { totalCount: 5, @@ -35,12 +29,18 @@ export const MOCKS = [ childTags: { totalCount: 5, }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], }, - cursor: '1', + cursor: 'subTag1', }, { node: { - _id: '2', + _id: 'subTag2', name: 'subTag 2', usersAssignedTo: { totalCount: 5, @@ -48,12 +48,18 @@ export const MOCKS = [ childTags: { totalCount: 0, }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], }, - cursor: '2', + cursor: 'subTag2', }, { node: { - _id: '3', + _id: 'subTag3', name: 'subTag 3', usersAssignedTo: { totalCount: 0, @@ -61,12 +67,18 @@ export const MOCKS = [ childTags: { totalCount: 5, }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], }, - cursor: '3', + cursor: 'subTag3', }, { node: { - _id: '4', + _id: 'subTag4', name: 'subTag 4', usersAssignedTo: { totalCount: 0, @@ -74,12 +86,18 @@ export const MOCKS = [ childTags: { totalCount: 0, }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], }, - cursor: '4', + cursor: 'subTag4', }, { node: { - _id: '5', + _id: 'subTag5', name: 'subTag 5', usersAssignedTo: { totalCount: 5, @@ -87,18 +105,120 @@ export const MOCKS = [ childTags: { totalCount: 5, }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], + }, + cursor: 'subTag5', + }, + { + node: { + _id: 'subTag6', + name: 'subTag 6', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 5, + }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], + }, + cursor: 'subTag6', + }, + { + node: { + _id: 'subTag7', + name: 'subTag 7', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 5, + }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], + }, + cursor: 'subTag7', + }, + { + node: { + _id: 'subTag8', + name: 'subTag 8', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 5, + }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], + }, + cursor: 'subTag8', + }, + { + node: { + _id: 'subTag9', + name: 'subTag 9', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 5, + }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], + }, + cursor: 'subTag9', + }, + { + node: { + _id: 'subTag10', + name: 'subTag 10', + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 5, + }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], }, - cursor: '5', + cursor: 'subTag10', }, ], pageInfo: { startCursor: '1', - endCursor: '5', + endCursor: '10', hasNextPage: true, hasPreviousPage: false, }, - totalCount: 6, + totalCount: 11, }, + ancestorTags: [], }, }, }, @@ -107,41 +227,48 @@ export const MOCKS = [ request: { query: USER_TAG_SUB_TAGS, variables: { - id: 'tag1', - after: '5', - before: null, - first: 5, - last: null, + id: '1', + after: '10', + first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { name: { starts_with: '' } }, + sortedBy: { id: 'DESCENDING' }, }, }, result: { data: { - getUserTag: { - name: 'tag1', + getChildTags: { + name: 'userTag 1', childTags: { edges: [ { node: { - _id: '6', - name: 'subTag 6', + _id: 'subTag11', + name: 'subTag 11', usersAssignedTo: { totalCount: 0, }, childTags: { totalCount: 0, }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], }, - cursor: '6', + cursor: 'subTag11', }, ], pageInfo: { - startCursor: '6', - endCursor: '6', + startCursor: '11', + endCursor: '11', hasNextPage: false, hasPreviousPage: true, }, - totalCount: 6, + totalCount: 11, }, + ancestorTags: [], }, }, }, @@ -150,93 +277,124 @@ export const MOCKS = [ request: { query: USER_TAG_SUB_TAGS, variables: { - id: 'tag1', - after: null, - before: '6', - first: null, - last: 5, + id: 'subTag1', + first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { name: { starts_with: '' } }, + sortedBy: { id: 'DESCENDING' }, }, }, result: { data: { - getUserTag: { - name: 'tag1', + getChildTags: { + name: 'subTag 1', childTags: { edges: [ { node: { - _id: '1', - name: 'subTag 1', + _id: 'subTag1.1', + name: 'subTag 1.1', usersAssignedTo: { totalCount: 5, }, childTags: { totalCount: 5, }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + { + _id: 'subTag1', + name: 'subTag 1', + }, + ], }, - cursor: '1', - }, - { - node: { - _id: '2', - name: 'subTag 2', - usersAssignedTo: { - totalCount: 5, - }, - childTags: { - totalCount: 0, - }, - }, - cursor: '2', + cursor: 'subTag1.1', }, + ], + pageInfo: { + startCursor: 'subTag1.1', + endCursor: 'subTag1.1', + hasNextPage: false, + hasPreviousPage: false, + }, + totalCount: 1, + }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], + }, + }, + }, + }, + { + request: { + query: USER_TAG_SUB_TAGS, + variables: { + id: '1', + first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { name: { starts_with: 'searchSubTag' } }, + sortedBy: { id: 'DESCENDING' }, + }, + }, + result: { + data: { + getChildTags: { + name: 'userTag 1', + childTags: { + edges: [ { node: { - _id: '3', - name: 'subTag 3', + _id: 'searchSubTag1', + name: 'searchSubTag 1', usersAssignedTo: { totalCount: 0, }, childTags: { - totalCount: 5, + totalCount: 0, }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], }, - cursor: '3', + cursor: 'searchSubTag1', }, { node: { - _id: '4', - name: 'subTag 4', + _id: 'searchSubTag2', + name: 'searchSubTag 2', usersAssignedTo: { totalCount: 0, }, childTags: { totalCount: 0, }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], }, - cursor: '4', - }, - { - node: { - _id: '5', - name: 'subTag 5', - usersAssignedTo: { - totalCount: 5, - }, - childTags: { - totalCount: 5, - }, - }, - cursor: '5', + cursor: 'searchSubTag2', }, ], pageInfo: { - startCursor: '1', - endCursor: '5', - hasNextPage: true, + startCursor: 'searchSubTag1', + endCursor: 'searchSubTag2', + hasNextPage: false, hasPreviousPage: false, }, - totalCount: 6, + totalCount: 2, }, + ancestorTags: [], }, }, }, @@ -246,98 +404,82 @@ export const MOCKS = [ query: USER_TAG_SUB_TAGS, variables: { id: '1', - after: null, - before: null, - first: 5, - last: null, + first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { name: { starts_with: 'searchSubTag' } }, + sortedBy: { id: 'ASCENDING' }, }, }, result: { data: { - getUserTag: { - name: 'subTag 1', + getChildTags: { + name: 'userTag 1', childTags: { - edges: [], + edges: [ + { + node: { + _id: 'searchSubTag2', + name: 'searchSubTag 2', + usersAssignedTo: { + totalCount: 0, + }, + childTags: { + totalCount: 0, + }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], + }, + cursor: 'searchSubTag2', + }, + { + node: { + _id: 'searchSubTag1', + name: 'searchSubTag 1', + usersAssignedTo: { + totalCount: 0, + }, + childTags: { + totalCount: 0, + }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], + }, + cursor: 'searchSubTag1', + }, + ], pageInfo: { - startCursor: null, - endCursor: null, + startCursor: 'searchSubTag2', + endCursor: 'searchSubTag1', hasNextPage: false, hasPreviousPage: false, }, - totalCount: 0, + totalCount: 2, }, + ancestorTags: [], }, }, }, }, - { - 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', + name: 'subTag 12', organizationId: '123', - parentTagId: 'tag1', + parentTagId: '1', }, }, result: { data: { createUserTag: { - _id: '7', - }, - }, - }, - }, - { - request: { - query: REMOVE_USER_TAG, - variables: { - id: '1', - }, - }, - result: { - data: { - removeUserTag: { - _id: '1', + _id: 'subTag12', }, }, }, @@ -349,65 +491,10 @@ 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', + id: '1', + first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { name: { starts_with: '' } }, + sortedBy: { id: 'DESCENDING' }, }, }, error: new Error('Mock Graphql Error'), diff --git a/src/screens/UserPortal/Campaigns/Campaigns.test.tsx b/src/screens/UserPortal/Campaigns/Campaigns.spec.tsx similarity index 88% rename from src/screens/UserPortal/Campaigns/Campaigns.test.tsx rename to src/screens/UserPortal/Campaigns/Campaigns.spec.tsx index 17b7eec4d5..09cde6b25d 100644 --- a/src/screens/UserPortal/Campaigns/Campaigns.test.tsx +++ b/src/screens/UserPortal/Campaigns/Campaigns.spec.tsx @@ -20,39 +20,57 @@ import i18nForTest from 'utils/i18nForTest'; import type { ApolloLink } from '@apollo/client'; import useLocalStorage from 'utils/useLocalstorage'; import Campaigns from './Campaigns'; +import { vi, it, expect, describe } from 'vitest'; import { EMPTY_MOCKS, MOCKS, USER_FUND_CAMPAIGNS_ERROR, } from './CampaignsMocks'; -jest.mock('react-toastify', () => ({ +/* Mocking 'react-toastify` */ +vi.mock('react-toastify', () => ({ toast: { - success: jest.fn(), - error: jest.fn(), + success: vi.fn(), + error: vi.fn(), }, })); -jest.mock('@mui/x-date-pickers/DateTimePicker', () => { + +/* Mocking `@mui/x-date-pickers/DateTimePicker` */ +vi.mock('@mui/x-date-pickers/DateTimePicker', async () => { + const actual = await vi.importActual( + '@mui/x-date-pickers/DesktopDateTimePicker', + ); return { - DateTimePicker: jest.requireActual( - '@mui/x-date-pickers/DesktopDateTimePicker', - ).DesktopDateTimePicker, + DateTimePicker: actual.DesktopDateTimePicker, }; }); + const { setItem } = useLocalStorage(); +/** + * Creates a mocked Apollo link for testing. + */ 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), ); +/* + * Renders the `Campaigns` component for testing. + * + * @param link - The mocked Apollo link used for testing. + * @returns The rendered result of the `Campaigns` component. + */ + const renderCampaigns = (link: ApolloLink): RenderResult => { return render( @@ -79,26 +97,38 @@ const renderCampaigns = (link: ApolloLink): RenderResult => { ); }; +/** + * Test suite for the User Campaigns screen. + */ describe('Testing User Campaigns Screen', () => { beforeEach(() => { setItem('userId', 'userId'); }); beforeAll(() => { - jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useParams: () => ({ orgId: 'orgId' }), - })); + /** + * Mocks the `useParams` function from `react-router-dom` to simulate URL parameters. + */ + vi.mock('react-router-dom', async () => { + const actual = await vi.importActual('react-router-dom'); + return { + ...actual, + useParams: vi.fn(() => ({ orgId: 'orgId' })), // Mock `useParams` + }; + }); }); afterAll(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); }); afterEach(() => { cleanup(); }); + /** + * Verifies that the User Campaigns screen renders correctly with mock data. + */ it('should render the User Campaigns screen', async () => { renderCampaigns(link1); await waitFor(() => { @@ -108,6 +138,9 @@ describe('Testing User Campaigns Screen', () => { }); }); + /** + * Ensures the app redirects to the fallback URL if `userId` is null in LocalStorage. + */ it('should redirect to fallback URL if userId is null in LocalStorage', async () => { setItem('userId', null); renderCampaigns(link1); @@ -116,7 +149,11 @@ describe('Testing User Campaigns Screen', () => { }); }); + /** + * Ensures the app redirects to the fallback URL if URL parameters are undefined. + */ it('should redirect to fallback URL if URL params are undefined', async () => { + vi.unmock('react-router-dom'); // unmocking to get real behavior from useParams render( diff --git a/src/screens/UserPortal/Campaigns/PledgeModal.test.tsx b/src/screens/UserPortal/Campaigns/PledgeModal.test.tsx index 3f299c5c48..b9fd7a7d4d 100644 --- a/src/screens/UserPortal/Campaigns/PledgeModal.test.tsx +++ b/src/screens/UserPortal/Campaigns/PledgeModal.test.tsx @@ -53,7 +53,7 @@ const pledgeProps: InterfacePledgeModal[] = [ _id: '1', firstName: 'John', lastName: 'Doe', - image: null, + image: undefined, }, ], }, @@ -77,7 +77,7 @@ const pledgeProps: InterfacePledgeModal[] = [ _id: '1', firstName: 'John', lastName: 'Doe', - image: null, + image: undefined, }, ], }, diff --git a/src/screens/UserPortal/Campaigns/PledgeModal.tsx b/src/screens/UserPortal/Campaigns/PledgeModal.tsx index d9076f52c8..44cc82401b 100644 --- a/src/screens/UserPortal/Campaigns/PledgeModal.tsx +++ b/src/screens/UserPortal/Campaigns/PledgeModal.tsx @@ -6,7 +6,7 @@ import { currencyOptions, currencySymbols } from 'utils/currency'; import type { InterfaceCreatePledge, InterfacePledgeInfo, - InterfacePledger, + InterfaceUserInfo, } from 'utils/interfaces'; import styles from './Campaigns.module.css'; import React, { useCallback, useEffect, useState } from 'react'; @@ -77,7 +77,7 @@ const PledgeModal: React.FC = ({ }); // State to manage the list of pledgers (users who are part of the pledge) - const [pledgers, setPledgers] = useState([]); + const [pledgers, setPledgers] = useState([]); // Mutation to update an existing pledge const [updatePledge] = useMutation(UPDATE_PLEDGE); @@ -252,7 +252,7 @@ const PledgeModal: React.FC = ({ readOnly={mode === 'edit' ? true : false} isOptionEqualToValue={(option, value) => option._id === value._id} filterSelectedOptions={true} - getOptionLabel={(member: InterfacePledger): string => + getOptionLabel={(member: InterfaceUserInfo): string => `${member.firstName} ${member.lastName}` } onChange={ diff --git a/src/screens/UserPortal/Chat/Chat.module.css b/src/screens/UserPortal/Chat/Chat.module.css index 5f9a672dea..aeab28f66c 100644 --- a/src/screens/UserPortal/Chat/Chat.module.css +++ b/src/screens/UserPortal/Chat/Chat.module.css @@ -1,6 +1,6 @@ .containerHeight { - padding: 1rem 1.5rem 0 calc(300px); - height: 100vh; + /* padding: 1rem 1.5rem 0 calc(300px); */ + /* height: 100vh; */ } .expand { @@ -32,7 +32,7 @@ } .containerHeight { - height: 100vh; + height: 88vh; } .mainContainer { @@ -188,8 +188,8 @@ /* For tablets */ @media (max-width: 820px) { .containerHeight { - height: 100vh; - padding: 2rem; + /* height: 100vh; */ + /* padding: 2rem; */ } .contract, @@ -216,3 +216,25 @@ .accordionBody::-webkit-scrollbar { display: none; } + +.filters { + padding: 20px 0px 0px 20px; + display: flex; + gap: 8px; +} + +.filterButton { + border-radius: 14px; + padding: 5px 10px; + background-color: white; + color: #a5a5a5; + border: none; + border: 1px solid #a5a5a5; +} + +.selectedBtn, +.filterButton:hover { + border: 1px solid #98e0b6; + background-color: #98e0b6; + color: rgb(255, 255, 255); +} diff --git a/src/screens/UserPortal/Chat/Chat.spec.tsx b/src/screens/UserPortal/Chat/Chat.spec.tsx new file mode 100644 index 0000000000..e691e4151d --- /dev/null +++ b/src/screens/UserPortal/Chat/Chat.spec.tsx @@ -0,0 +1,4414 @@ +import React from 'react'; +import { + act, + fireEvent, + render, + screen, + waitFor, +} from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import { BrowserRouter } from 'react-router-dom'; +import { Provider } from 'react-redux'; +import { expect, describe, test, vi } from 'vitest'; +import { store } from 'state/store'; +import i18nForTest from 'utils/i18nForTest'; +import { I18nextProvider } from 'react-i18next'; +import Chat from './Chat'; +import { + USERS_CONNECTION_LIST, + USER_JOINED_ORGANIZATIONS, +} from 'GraphQl/Queries/Queries'; +import { + MARK_CHAT_MESSAGES_AS_READ, + MESSAGE_SENT_TO_CHAT, +} from 'GraphQl/Mutations/OrganizationMutations'; +import { + CHATS_LIST, + CHAT_BY_ID, + GROUP_CHAT_LIST, + UNREAD_CHAT_LIST, +} from 'GraphQl/Queries/PlugInQueries'; +import useLocalStorage from 'utils/useLocalstorage'; + +/** + * Unit tests for the ChatScreen component. + * These tests covers all areas + * Covers: + * - Rendering of UI elements. + * - Contact selection functionality. + * - Direct and group chat creation workflows. + * - Sidebar behavior in desktop and mobile views. + * + * Uses Vitest for testing and Apollo MockedProvider for mocking GraphQL queries. + */ + +vi.mock('../../../components/UserPortal/ChatRoom/ChatRoom', () => ({ + default: () =>
Mocked ChatRoom
, +})); + +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} +const { setItem } = useLocalStorage(); + +const MARK_CHAT_MESSAGES_AS_READ_MOCK = [ + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: null, + chatId: '', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: null, + chatId: '', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: '1', + chatId: '', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: '1', + chatId: '', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, + { + request: { + query: MARK_CHAT_MESSAGES_AS_READ, + variables: { + userId: '1', + chatId: '', + }, + }, + result: { + data: { + markChatMessagesAsRead: { + _id: '1', + }, + }, + }, + }, +]; + +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: 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: [], + }, + ], + }, + }, + }, + }, +]; + +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: { + messageSentToChat: { + _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: { + messageSentToChat: { + _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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + }), + }, + }, + }, + }, + { + 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + }), + }, + }, + }, + }, + { + 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: '', + }, + ], + admins: [], + }, + }, + }, + }, +]; + +const CHATS_LIST_MOCK = [ + { + request: { + query: CHATS_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844efc814dd40sassxaasfgh03db811c4', + image: '', + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + { + _id: '65844efc8q14ddgh4003db811c4', + isGroup: true, + image: '', + 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: CHATS_LIST, + variables: { + id: '', + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844efc814dd40fgh03db811c4', + isGroup: true, + image: '', + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + { + _id: '65844efc814ddgh4003db811c4', + isGroup: true, + image: '', + 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: CHATS_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844efc814dd40fggfdh03db811c4', + isGroup: true, + image: '', + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + { + _id: '65844efc814ddgh4003db811c4', + isGroup: true, + image: '', + 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: CHATS_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844efc814dd40wasxfgh03db811c4', + isGroup: true, + image: '', + 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + { + _id: '65844efc814ddgh4003db811c4', + isGroup: true, + image: '', + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: CHATS_LIST, + variables: { + id: '', + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844ghjefc814dd4003db811c4', + isGroup: true, + image: '', + 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + { + _id: 'ujhgtrdtyuiop', + isGroup: true, + image: '', + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: CHATS_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844efc814dhjmkdftyd4003db811c4', + isGroup: true, + image: '', + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + { + _id: '65844ewsedrffc814dd4003db811c4', + isGroup: true, + image: '', + 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: CHATS_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844efc814dhjmkdftyd4003db811c4', + isGroup: true, + image: '', + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + { + _id: '65844ewsedrffc814dd4003db811c4', + isGroup: true, + image: '', + 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: CHATS_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844efc814dhjmkdftyd4003db811c4', + isGroup: true, + image: '', + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + { + _id: '65844ewsedrffc814dd4003db811c4', + isGroup: true, + image: '', + 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: CHATS_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + chatsByUserId: [ + { + _id: '65844efc814dhjmkdftyd4003db811c4', + isGroup: true, + image: '', + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + { + _id: '65844ewsedrffc814dd4003db811c4', + isGroup: true, + image: '', + 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, +]; + +const GROUP_CHAT_BY_ID_QUERY_MOCK = [ + { + request: { + query: CHAT_BY_ID, + variables: { + id: '', + }, + }, + result: { + data: { + chatById: { + _id: '65844efc814dd4003db811c4', + isGroup: true, + image: '', + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + }, + }, + }, +]; + +const UNREAD_CHAT_LIST_QUERY_MOCK = [ + { + request: { + query: UNREAD_CHAT_LIST, + variables: {}, + }, + result: { + data: { + getUnreadChatsByUserId: [ + { + _id: '1', + createdAt: '2345678903456', + isGroup: false, + image: '', + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + ], + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: {}, + }, + result: { + data: { + getUnreadChatsByUserId: [ + { + _id: '1', + createdAt: '2345678903456', + isGroup: false, + image: '', + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + ], + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: {}, + }, + result: { + data: { + getUnreadChatsByUserId: [ + { + _id: '1', + createdAt: '2345678903456', + isGroup: false, + image: '', + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + ], + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: {}, + }, + result: { + data: { + getUnreadChatsByUserId: [ + { + _id: '1', + createdAt: '2345678903456', + isGroup: false, + image: '', + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + ], + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + getUnreadChatsByUserId: [ + { + _id: '1', + createdAt: '2345678903456', + isGroup: false, + image: '', + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + ], + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + getUnreadChatsByUserId: [ + { + _id: '1', + createdAt: '2345678903456', + isGroup: false, + image: '', + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + ], + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: { + id: '1', + }, + }, + result: { + data: { + getUnreadChatsByUserId: [ + { + _id: '1', + createdAt: '2345678903456', + isGroup: false, + image: '', + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + ], + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + getUnreadChatsByUserId: [ + { + _id: '1', + createdAt: '2345678903456', + isGroup: false, + image: '', + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + ], + }, + }, + }, + { + request: { + query: UNREAD_CHAT_LIST, + variables: { + id: null, + }, + }, + result: { + data: { + getUnreadChatsByUserId: [ + { + _id: '1', + createdAt: '2345678903456', + isGroup: false, + image: '', + 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, + media: 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: '', + }, + ], + admins: [], + unseenMessagesByUsers: JSON.stringify({ + '1': 0, + '2': 0, + }), + }, + ], + }, + }, + }, +]; + +const GROUP_CHAT_LIST_QUERY_MOCK = [ + { + request: { + query: GROUP_CHAT_LIST, + variables: {}, + }, + result: { + data: { + getGroupChatsByUserId: [ + { + _id: '65844efc814dd4003db811c4', + isGroup: true, + image: '', + 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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: GROUP_CHAT_LIST, + variables: {}, + }, + result: { + data: { + getGroupChatsByUserId: [ + { + _id: '65844efc814dd4003db811c4', + isGroup: true, + image: '', + 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', + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: GROUP_CHAT_LIST, + variables: {}, + }, + result: { + data: { + getGroupChatsByUserId: [ + { + _id: '65844efc814dd4003db811c4', + isGroup: true, + image: '', + 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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: GROUP_CHAT_LIST, + variables: {}, + }, + result: { + data: { + getGroupChatsByUserId: [ + { + _id: '65844efc814dd4003db811c4', + isGroup: true, + image: '', + 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', + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: GROUP_CHAT_LIST, + variables: {}, + }, + result: { + data: { + getGroupChatsByUserId: [ + { + _id: '65844efc814dd4003db811c4', + isGroup: true, + image: '', + 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', + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: GROUP_CHAT_LIST, + variables: {}, + }, + result: { + data: { + getGroupChatsByUserId: [ + { + _id: '65844efc814dd4003db811c4', + isGroup: true, + image: '', + 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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: GROUP_CHAT_LIST, + variables: {}, + }, + result: { + data: { + getGroupChatsByUserId: [ + { + _id: '65844efc814dd4003db811c4', + isGroup: true, + image: '', + 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', + media: null, + 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, + { + request: { + query: GROUP_CHAT_LIST, + variables: {}, + }, + result: { + data: { + getGroupChatsByUserId: [ + { + _id: '65844efc814dd4003db811c4', + isGroup: true, + image: '', + 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, + media: 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: '', + }, + ], + admins: [ + { + _id: '1', + firstName: 'Disha', + lastName: 'Talreja', + email: 'disha@example.com', + image: '', + }, + ], + unseenMessagesByUsers: JSON.stringify({ + '1': 1, + '2': 1, + '3': 1, + '4': 1, + '5': 1, + }), + }, + ], + }, + }, + }, +]; + +describe('Testing Chat Screen [User Portal]', () => { + Object.defineProperty(window, 'matchMedia', { + writable: true, + value: vi.fn().mockImplementation((query) => ({ + matches: false, + media: query, + onchange: null, + addListener: vi.fn(), + removeListener: vi.fn(), + addEventListener: vi.fn(), + removeEventListener: vi.fn(), + dispatchEvent: vi.fn(), + })), + }); + + beforeEach(() => { + setItem('userId', '1'); + vi.clearAllMocks(); + localStorage.clear(); + vi.resetModules(); + }); + + afterEach(() => { + localStorage.clear(); + }); + + 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, + ...UNREAD_CHAT_LIST_QUERY_MOCK, + ...GROUP_CHAT_LIST_QUERY_MOCK, + ...MARK_CHAT_MESSAGES_AS_READ_MOCK, + ]; + + test('Screen should be rendered properly', async () => { + render( + + + + + + + + + , + ); + await wait(); + }); + + test('User is able to select a contact', async () => { + render( + + + + + + + + + , + ); + + await wait(); + expect(await screen.findByText('Messages')).toBeInTheDocument(); + expect( + await screen.findByTestId('contactCardContainer'), + ).toBeInTheDocument(); + }); + + test('create new direct chat', async () => { + 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 closeButton = screen.getByRole('button', { name: /close/i }); + expect(closeButton).toBeInTheDocument(); + + const submitBtn = await screen.findByTestId('submitBtn'); + expect(submitBtn).toBeInTheDocument(); + + fireEvent.click(closeButton); + }); + + test('create new group chat', async () => { + 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); + }); + + // filter chat test + test('Testing chat filters', async () => { + setItem('userId', '1'); + + render( + + + + + + + + + , + ); + await waitFor(async () => { + expect(await screen.findByTestId('unreadChat')).toBeInTheDocument(); + }); + await act(async () => { + fireEvent.click(await screen.findByTestId('unreadChat')); + }); + + await wait(1000); + + await act(async () => { + fireEvent.click(await screen.findByTestId('groupChat')); + }); + + await wait(1000); + + await act(async () => { + fireEvent.click(await screen.findByTestId('allChat')); + }); + }); +}); diff --git a/src/screens/UserPortal/Chat/Chat.test.tsx b/src/screens/UserPortal/Chat/Chat.test.tsx deleted file mode 100644 index d5e8049687..0000000000 --- a/src/screens/UserPortal/Chat/Chat.test.tsx +++ /dev/null @@ -1,1695 +0,0 @@ -import React from 'react'; -import { - act, - fireEvent, - render, - screen, - waitFor, -} 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 './Chat'; -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 { 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: 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: [], - }, - ], - }, - }, - }, - }, -]; - -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: '', - 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: '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 resizeWindow = (width: number): void => { - window.innerWidth = width; - fireEvent(window, new Event('resize')); -}; - -async function wait(ms = 100): Promise { - await act(() => { - return new Promise((resolve) => { - setTimeout(resolve, ms); - }); - }); -} - -describe('Testing Chat Screen [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('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( - - - - - - - - - , - ); - await wait(); - }); - - 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( - - - - - - - - - , - ); - - await wait(); - - expect(await screen.findByText('Messages')).toBeInTheDocument(); - - expect( - await screen.findByTestId('contactCardContainer'), - ).toBeInTheDocument(); - }); - - 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( - - - - - - - - - , - ); - - 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(); - - const submitBtn = await screen.findByTestId('submitBtn'); - expect(submitBtn).toBeInTheDocument(); - - fireEvent.click(closeButton); - }); - - 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( - - - - - - - - - , - ); - - 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('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(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 441ce7d4ba..0155f3ee0a 100644 --- a/src/screens/UserPortal/Chat/Chat.tsx +++ b/src/screens/UserPortal/Chat/Chat.tsx @@ -1,18 +1,21 @@ import React, { useEffect, useState } from 'react'; -import { useQuery } from '@apollo/client'; +import { useMutation, useQuery } from '@apollo/client'; import { useTranslation } from 'react-i18next'; 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 { + CHATS_LIST, + GROUP_CHAT_LIST, + UNREAD_CHAT_LIST, +} from 'GraphQl/Queries/PlugInQueries'; import CreateGroupChat from '../../../components/UserPortal/CreateGroupChat/CreateGroupChat'; import CreateDirectChat from 'components/UserPortal/CreateDirectChat/CreateDirectChat'; +import { MARK_CHAT_MESSAGES_AS_READ } from 'GraphQl/Mutations/OrganizationMutations'; interface InterfaceContactCardProps { id: string; @@ -21,6 +24,8 @@ interface InterfaceContactCardProps { selectedContact: string; setSelectedContact: React.Dispatch>; isGroup: boolean; + unseenMessages: number; + lastMessage: string; } /** * The `chat` component provides a user interface for interacting with contacts and chat rooms within an organization. @@ -48,15 +53,62 @@ interface InterfaceContactCardProps { * * @returns The rendered `chat` 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 Chat = { + _id: string; + isGroup: boolean; + name: string; + image: string; + messages: DirectMessage[]; + users: { + _id: string; + firstName: string; + lastName: string; + email: string; + image: string; + }[]; + unseenMessagesByUsers: string; +}; export default function chat(): JSX.Element { const { t } = useTranslation('translation', { - keyPrefix: 'chat', + keyPrefix: 'userChat', }); const { t: tCommon } = useTranslation('common'); const [hideDrawer, setHideDrawer] = useState(null); - const [chats, setChats] = useState([]); + const [chats, setChats] = useState([]); const [selectedContact, setSelectedContact] = useState(''); + const [filterType, setFilterType] = useState('all'); const { getItem } = useLocalStorage(); const userId = getItem('userId'); @@ -74,6 +126,25 @@ export default function chat(): JSX.Element { }; }, []); + React.useEffect(() => { + if (filterType === 'all') { + chatsListRefetch(); + if (chatsListData && chatsListData.chatsByUserId) { + setChats(chatsListData.chatsByUserId); + } + } else if (filterType === 'unread') { + unreadChatListRefetch(); + if (unreadChatListData && unreadChatListData.getUnreadChatsByUserId) { + setChats(unreadChatListData.getUnreadChatsByUserId); + } + } else if (filterType === 'group') { + groupChatListRefetch(); + if (groupChatListData && groupChatListData.getGroupChatsByUserId) { + setChats(groupChatListData.getGroupChatsByUserId); + } + } + }, [filterType]); + const [createDirectChatModalisOpen, setCreateDirectChatModalisOpen] = useState(false); @@ -105,60 +176,40 @@ export default function chat(): JSX.Element { }, }); + const { data: groupChatListData, refetch: groupChatListRefetch } = + useQuery(GROUP_CHAT_LIST); + + const { data: unreadChatListData, refetch: unreadChatListRefetch } = + useQuery(UNREAD_CHAT_LIST); + + const [markChatMessagesAsRead] = useMutation(MARK_CHAT_MESSAGES_AS_READ, { + variables: { + chatId: selectedContact, + userId: userId, + }, + }); + + useEffect(() => { + markChatMessagesAsRead().then(() => { + chatsListRefetch({ id: userId }); + }); + }, [selectedContact]); + React.useEffect(() => { - if (chatsListData) { + if (chatsListData && chatsListData?.chatsByUserId.length) { setChats(chatsListData.chatsByUserId); } }, [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 ? ( - - ) : ( - - )} -
-

Messages

+

{t('messages')}

- New Chat + {t('newChat')} - New Group Chat + {t('newGroupChat')} Starred Messages @@ -188,45 +239,102 @@ export default function chat(): JSX.Element {
{chatsListLoading ? (
- Loading... + {tCommon('loading')}
) : ( -
- {!!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 ( - - ); - })} -
+ <> +
+ {/* three buttons to filter unread, all and group chats. All selected by default. */} + + + +
+ +
+ {!!chats.length && + chats.map((chat: Chat) => { + 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 + ? chat.image + : userId + ? chat.users[1]?.image + : chat.users[0]?.image, + setSelectedContact, + selectedContact, + isGroup: chat.isGroup, + unseenMessages: JSON.parse( + chat.unseenMessagesByUsers, + )[userId], + lastMessage: + chat.messages[chat.messages.length - 1] + ?.messageContent, + }; + return ( + + ); + })} +
+ )}
- +
diff --git a/src/screens/UserPortal/Donate/Donate.test.tsx b/src/screens/UserPortal/Donate/Donate.spec.tsx similarity index 93% rename from src/screens/UserPortal/Donate/Donate.test.tsx rename to src/screens/UserPortal/Donate/Donate.spec.tsx index c4d435415e..b13056f5f9 100644 --- a/src/screens/UserPortal/Donate/Donate.test.tsx +++ b/src/screens/UserPortal/Donate/Donate.spec.tsx @@ -1,8 +1,14 @@ +/** + * Unit tests for the Donate component. + * + * This file contains tests for the Donate component to ensure it behaves as expected + * under various scenarios. + */ import React, { act } from 'react'; import { render, screen } from '@testing-library/react'; import { MockedProvider } from '@apollo/react-testing'; import { I18nextProvider } from 'react-i18next'; - +import { vi } from 'vitest'; import { ORGANIZATION_DONATION_CONNECTION_LIST, USER_ORGANIZATION_CONNECTION, @@ -132,35 +138,35 @@ async function wait(ms = 100): Promise { }); } -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useParams: () => ({ orgId: '' }), +vi.mock('react-router-dom', async () => ({ + ...(await vi.importActual('react-router-dom')), + useParams: vi.fn(() => ({ orgId: '' })), })); -jest.mock('react-toastify', () => ({ +vi.mock('react-toastify', () => ({ toast: { - error: jest.fn(), - success: jest.fn(), + error: vi.fn(), + success: vi.fn(), }, })); describe('Testing Donate Screen [User Portal]', () => { Object.defineProperty(window, 'matchMedia', { writable: true, - value: jest.fn().mockImplementation((query) => ({ + value: vi.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(), + addListener: vi.fn(), // Deprecated + removeListener: vi.fn(), // Deprecated + addEventListener: vi.fn(), + removeEventListener: vi.fn(), + dispatchEvent: vi.fn(), })), }); beforeEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); }); test('Screen should be rendered properly', async () => { diff --git a/src/screens/UserPortal/Events/Events.test.tsx b/src/screens/UserPortal/Events/Events.spec.tsx similarity index 62% rename from src/screens/UserPortal/Events/Events.test.tsx rename to src/screens/UserPortal/Events/Events.spec.tsx index e5ef6d2b03..0e49402019 100644 --- a/src/screens/UserPortal/Events/Events.test.tsx +++ b/src/screens/UserPortal/Events/Events.spec.tsx @@ -1,5 +1,5 @@ import React, { act } from 'react'; -import { 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,35 +19,51 @@ import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { ThemeProvider } from 'react-bootstrap'; import { createTheme } from '@mui/material'; import useLocalStorage from 'utils/useLocalstorage'; +import { vi } from 'vitest'; -const { setItem, getItem } = useLocalStorage(); +/** + * Unit tests for the Events component. + * + * This file contains tests to verify the functionality and behavior of the Events component + * under various scenarios, including successful event creation, date/time picker handling, + * calendar view toggling, and error handling. Mocked dependencies are used to ensure isolated testing. + */ -jest.mock('react-toastify', () => ({ +const { setItem } = useLocalStorage(); + +vi.mock('react-toastify', () => ({ toast: { - error: jest.fn(), - info: jest.fn(), - success: jest.fn(), + error: vi.fn(), + info: vi.fn(), + success: vi.fn(), }, })); -jest.mock('@mui/x-date-pickers/DatePicker', () => { +vi.mock('@mui/x-date-pickers/DatePicker', async () => { + const desktopDatePickerModule = await vi.importActual( + '@mui/x-date-pickers/DesktopDatePicker', + ); return { - DatePicker: jest.requireActual('@mui/x-date-pickers/DesktopDatePicker') - .DesktopDatePicker, + DatePicker: desktopDatePickerModule.DesktopDatePicker, }; }); -jest.mock('@mui/x-date-pickers/TimePicker', () => { +vi.mock('@mui/x-date-pickers/TimePicker', async () => { + const timePickerModule = await vi.importActual( + '@mui/x-date-pickers/DesktopTimePicker', + ); return { - TimePicker: jest.requireActual('@mui/x-date-pickers/DesktopTimePicker') - .DesktopTimePicker, + TimePicker: timePickerModule.DesktopTimePicker, }; }); -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useParams: () => ({ orgId: '' }), -})); +vi.mock('react-router-dom', async () => { + const actual = await vi.importActual('react-router-dom'); + return { + ...actual, + useParams: () => ({ orgId: '' }), + }; +}); const theme = createTheme({ palette: { @@ -82,6 +98,7 @@ const MOCKS = [ recurring: false, isPublic: true, isRegisterable: false, + createChat: false, creator: { _id: '63d649417ffe6e4d5174ea32', firstName: 'Noble', @@ -113,6 +130,7 @@ const MOCKS = [ recurring: false, isPublic: true, isRegisterable: true, + createChat: true, creator: { _id: '63d649417ffe6e4d5174ea32', firstName: 'Noble', @@ -163,6 +181,7 @@ const MOCKS = [ recurring: false, isPublic: true, isRegisterable: false, + createChat: false, creator: { _id: '63d649417ffe6e4d5174ea32', firstName: 'Noble', @@ -191,7 +210,168 @@ const MOCKS = [ variables: { title: 'testEventTitle', description: 'testEventDescription', + isPublic: true, + recurring: false, + isRegisterable: true, + organizationId: '', + startDate: dayjs(new Date()).format('YYYY-MM-DD'), + endDate: dayjs(new Date()).format('YYYY-MM-DD'), + allDay: true, + location: 'testEventLocation', + startTime: null, + endTime: null, + createChat: false, + }, + }, + result: { + data: { + createEvent: { + _id: '2', + }, + }, + }, + }, + { + request: { + query: CREATE_EVENT_MUTATION, + variables: { + title: 'testEventTitle', + description: 'testEventDescription', + isPublic: true, + recurring: false, + isRegisterable: true, + organizationId: '', + startDate: dayjs(new Date()).format('YYYY-MM-DD'), + endDate: dayjs(new Date()).format('YYYY-MM-DD'), + allDay: true, + location: 'testEventLocation', + startTime: null, + endTime: null, + createChat: false, + }, + }, + result: { + data: { + createEvent: { + _id: '2', + }, + }, + }, + }, + { + request: { + query: CREATE_EVENT_MUTATION, + variables: { + title: 'testEventTitle', + description: 'testEventDescription', + isPublic: true, + recurring: false, + isRegisterable: true, + organizationId: '', + startDate: dayjs(new Date()).format('YYYY-MM-DD'), + endDate: dayjs(new Date()).format('YYYY-MM-DD'), + allDay: true, + location: 'testEventLocation', + startTime: null, + endTime: null, + createChat: false, + }, + }, + result: { + data: { + createEvent: { + _id: '2', + }, + }, + }, + }, + { + request: { + query: CREATE_EVENT_MUTATION, + variables: { + title: 'testEventTitle', + description: 'testEventDescription', + location: 'testEventLocation', + isPublic: true, + recurring: false, + isRegisterable: true, + createChat: false, + organizationId: '', + startDate: dayjs(new Date()).format('YYYY-MM-DD'), + endDate: dayjs(new Date()).format('YYYY-MM-DD'), + allDay: false, + startTime: '08:00:00', + endTime: '10:00:00', + }, + }, + result: { + data: { + createEvent: { + _id: '2', + }, + }, + }, + }, + { + request: { + query: CREATE_EVENT_MUTATION, + variables: { + title: 'testEventTitle', + description: 'testEventDescription', + isPublic: true, + recurring: false, + isRegisterable: true, + organizationId: '', + startDate: '2024-10-27', + endDate: '2024-10-27', + allDay: false, + location: 'testEventLocation', + startTime: '08:00:00Z', + endTime: '10:00:00Z', + createChat: false, + }, + }, + result: { + data: { + createEvent: { + _id: '2', + }, + }, + }, + }, + { + request: { + query: CREATE_EVENT_MUTATION, + variables: { + title: 'testEventTitle', + description: 'testEventDescription', + isPublic: true, + recurring: false, + isRegisterable: true, + organizationId: '', + startDate: dayjs(new Date()).format('YYYY-MM-DD'), + endDate: dayjs(new Date()).format('YYYY-MM-DD'), + allDay: false, location: 'testEventLocation', + startTime: '08:00:00Z', + endTime: '10:00:00Z', + createChat: false, + }, + }, + result: { + data: { + createEvent: { + _id: '2', + }, + }, + }, + }, + { + request: { + query: CREATE_EVENT_MUTATION, + variables: { + title: 'testEventTitle', + description: 'testEventDescription', isPublic: true, recurring: false, isRegisterable: true, @@ -199,6 +379,35 @@ const MOCKS = [ startDate: dayjs(new Date()).format('YYYY-MM-DD'), endDate: dayjs(new Date()).format('YYYY-MM-DD'), allDay: false, + location: 'testEventLocation', + startTime: '08:00:00Z', + endTime: '10:00:00Z', + createChat: false, + }, + }, + result: { + data: { + createEvent: { + _id: '2', + }, + }, + }, + }, + { + request: { + query: CREATE_EVENT_MUTATION, + variables: { + title: 'testEventTitle', + description: 'testEventDescription', + location: 'testEventLocation', + isPublic: true, + recurring: false, + isRegisterable: true, + createChat: false, + organizationId: '', + startDate: dayjs(new Date()).format('YYYY-MM-DD'), + endDate: dayjs(new Date()).format('YYYY-MM-DD'), + allDay: false, startTime: '08:00:00', endTime: '10:00:00', }, @@ -221,6 +430,34 @@ const MOCKS = [ isPublic: true, recurring: false, isRegisterable: true, + createChat: false, + organizationId: '', + startDate: dayjs(new Date()).format('YYYY-MM-DD'), + endDate: dayjs(new Date()).format('YYYY-MM-DD'), + allDay: false, + startTime: '08:00:00', + endTime: '10:00:00', + }, + }, + result: { + data: { + createEvent: { + _id: '2', + }, + }, + }, + }, + { + request: { + query: CREATE_EVENT_MUTATION, + variables: { + title: 'testEventTitle', + description: 'testEventDescription', + location: 'testEventLocation', + isPublic: true, + recurring: false, + isRegisterable: true, + createChat: true, organizationId: '', startDate: dayjs(new Date()).format('YYYY-MM-DD'), endDate: dayjs(new Date()).format('YYYY-MM-DD'), @@ -252,19 +489,19 @@ async function wait(ms = 100): Promise { describe('Testing Events Screen [User Portal]', () => { Object.defineProperty(window, 'matchMedia', { writable: true, - value: jest.fn().mockImplementation((query) => ({ + value: vi.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(), + addListener: vi.fn(), // Deprecated + removeListener: vi.fn(), // Deprecated + addEventListener: vi.fn(), + removeEventListener: vi.fn(), + dispatchEvent: vi.fn(), })), }); - test('Screen should be rendered properly', async () => { + it('Screen should be rendered properly', async () => { render( @@ -283,7 +520,7 @@ describe('Testing Events Screen [User Portal]', () => { await wait(); }); - test('Create event works as expected when event is not an all day event.', async () => { + it('Create event works as expected when event is not an all day event.', async () => { render( @@ -330,18 +567,21 @@ describe('Testing Events Screen [User Portal]', () => { userEvent.click(screen.getByTestId('recurringEventCheck')); userEvent.click(screen.getByTestId('recurringEventCheck')); + userEvent.click(screen.getByTestId('createChatCheck')); + userEvent.click(screen.getByTestId('createChatCheck')); + userEvent.click(screen.getByTestId('allDayEventCheck')); userEvent.click(screen.getByTestId('createEventBtn')); await wait(); - expect(toast.success).toBeCalledWith( + expect(toast.success).toHaveBeenCalledWith( 'Event created and posted successfully.', ); }); - test('Create event works as expected when event is an all day event.', async () => { + it('Create event works as expected when event is an all day event.', async () => { render( @@ -379,12 +619,12 @@ describe('Testing Events Screen [User Portal]', () => { await wait(); - expect(toast.success).toBeCalledWith( + expect(toast.success).toHaveBeenCalledWith( 'Event created and posted successfully.', ); }); - test('Switch to calendar view works as expected.', async () => { + it('Switch to calendar view works as expected.', async () => { render( @@ -413,7 +653,7 @@ describe('Testing Events Screen [User Portal]', () => { expect(screen.getByText('Sun')).toBeInTheDocument(); }); - test('Testing DatePicker and TimePicker', async () => { + it('Testing DatePicker and TimePicker', async () => { render( @@ -430,31 +670,39 @@ describe('Testing Events Screen [User Portal]', () => { , ); - await wait(); - - const startDate = '03/23/2024'; - const endDate = '04/23/2024'; - const startTime = '02:00 PM'; - const endTime = '06:00 PM'; - userEvent.click(screen.getByTestId('createEventModalBtn')); + // MM/DD/YYYY + const startDate = new Date(); + const endDate = new Date(); + const startTime = '08:00 AM'; + const endTime = '10:00 AM'; + + await waitFor(() => { + expect(screen.getByLabelText('Start Date')).toBeInTheDocument(); + expect(screen.getByLabelText('End Date')).toBeInTheDocument(); + }); expect(endDate).not.toBeNull(); const endDateDatePicker = screen.getByLabelText('End Date'); expect(startDate).not.toBeNull(); const startDateDatePicker = screen.getByLabelText('Start Date'); + const startDateDayjs = dayjs(startDate); + const endDateDayjs = dayjs(endDate); + fireEvent.change(startDateDatePicker, { - target: { value: startDate }, + target: { value: startDateDayjs.format('MM/DD/YYYY') }, }); fireEvent.change(endDateDatePicker, { - target: { value: endDate }, + target: { value: endDateDayjs.format('MM/DD/YYYY') }, }); - await wait(); - - expect(endDateDatePicker).toHaveValue(endDate); - expect(startDateDatePicker).toHaveValue(startDate); + await waitFor(() => { + expect(startDateDatePicker).toHaveValue( + startDateDayjs.format('MM/DD/YYYY'), + ); + expect(endDateDatePicker).toHaveValue(endDateDayjs.format('MM/DD/YYYY')); + }); userEvent.click(screen.getByTestId('allDayEventCheck')); @@ -475,7 +723,7 @@ describe('Testing Events Screen [User Portal]', () => { expect(startTimePicker).toHaveValue(startTime); }); - test('EndDate null', async () => { + it('EndDate null', async () => { render( diff --git a/src/screens/UserPortal/Events/Events.tsx b/src/screens/UserPortal/Events/Events.tsx index d3fabf9469..079e1d5f8c 100644 --- a/src/screens/UserPortal/Events/Events.tsx +++ b/src/screens/UserPortal/Events/Events.tsx @@ -63,6 +63,7 @@ export default function events(): JSX.Element { const [endTime, setEndTime] = React.useState('10:00:00'); const [viewType, setViewType] = React.useState(ViewType.MONTH); const [createEventModal, setCreateEventmodalisOpen] = React.useState(false); + const [createChatCheck, setCreateChatCheck] = React.useState(false); const { orgId: organizationId } = useParams(); // Query to fetch events for the organization @@ -115,8 +116,9 @@ export default function events(): JSX.Element { endDate: dayjs(endDate).format('YYYY-MM-DD'), allDay: isAllDay, location: eventLocation, - startTime: !isAllDay ? startTime : null, - endTime: !isAllDay ? endTime : null, + startTime: !isAllDay ? startTime + 'Z' : null, + endTime: !isAllDay ? endTime + 'Z' : null, + createChat: createChatCheck, }, }); @@ -134,6 +136,7 @@ export default function events(): JSX.Element { } setCreateEventmodalisOpen(false); } catch (error: unknown) { + console.error('create event error', error); /* istanbul ignore next */ errorHandler(t, error); } @@ -390,6 +393,21 @@ export default function events(): JSX.Element { />
+
+
+ + + setCreateChatCheck(!createChatCheck) + } + /> +
+
+ + { + setShowModal(false); + setVerificationStep(false); + setEmail(''); + setError(''); + }} + > + + + Leave Joined Organization + + + + {!verificationStep ? ( + <> +

Are you sure you want to leave this organization?

+

+ This action cannot be undone, and you may need to request access + again if you reconsider. +

+ + ) : ( +
+ + + Enter your email to confirm: + + setEmail(e.target.value)} + onKeyDown={handleKeyPress} + aria-label="confirm-email-input" + /> + + {error && ( + + {error} + + )} +
+ )} +
+ + {!verificationStep ? ( + <> + + + + ) : ( + <> + + + + )} + +
+
+ ); +}; + +export default LeaveOrganization; diff --git a/src/screens/UserPortal/Organizations/Organizations.test.tsx b/src/screens/UserPortal/Organizations/Organizations.spec.tsx similarity index 95% rename from src/screens/UserPortal/Organizations/Organizations.test.tsx rename to src/screens/UserPortal/Organizations/Organizations.spec.tsx index f8a6fc06a5..0aafba3b55 100644 --- a/src/screens/UserPortal/Organizations/Organizations.test.tsx +++ b/src/screens/UserPortal/Organizations/Organizations.spec.tsx @@ -18,6 +18,10 @@ import Organizations from './Organizations'; import React, { act } from 'react'; const { getItem } = useLocalStorage(); +/** + * Mock data for GraphQL queries. + */ + const MOCKS = [ { request: { @@ -317,6 +321,10 @@ const MOCKS = [ }, ]; +/** + * Custom Mock Link for handling static GraphQL mocks. + */ + const link = new StaticMockLink(MOCKS, true); async function wait(ms = 100): Promise { @@ -333,6 +341,9 @@ const resizeWindow = (width: number): void => { }; describe('Testing Organizations Screen [User Portal]', () => { + /** + * Test to ensure the screen is rendered properly. + */ test('Screen should be rendered properly', async () => { render( @@ -347,8 +358,13 @@ describe('Testing Organizations Screen [User Portal]', () => { ); await wait(); + expect(screen.getByText('My Organizations')).toBeInTheDocument(); }); + /** + * Test to check if the search functionality works as expected. + */ + test('Search works properly', async () => { render( @@ -374,6 +390,10 @@ describe('Testing Organizations Screen [User Portal]', () => { await wait(); }); + /** + * Test to verify the mode change to joined organizations. + */ + test('Mode is changed to joined organizations', async () => { render( @@ -397,6 +417,10 @@ describe('Testing Organizations Screen [User Portal]', () => { expect(screen.queryAllByText('joinedOrganization')).not.toBe([]); }); + /** + * Test case to ensure the mode can be changed to display created organizations. + */ + test('Mode is changed to created organizations', async () => { render( @@ -420,6 +444,10 @@ describe('Testing Organizations Screen [User Portal]', () => { expect(screen.queryAllByText('createdOrganization')).not.toBe([]); }); + /** + * Test case to check if the "Join Now" button renders correctly on the page. + */ + test('Join Now button render correctly', async () => { render( @@ -463,6 +491,10 @@ describe('Testing Organizations Screen [User Portal]', () => { expect(screen.queryAllByText('createdOrganization')).not.toBe([]); }); + /** + * Test case to ensure the sidebar is functional, including opening and closing actions. + */ + test('Testing Sidebar', async () => { render( diff --git a/src/screens/UserPortal/People/People.test.tsx b/src/screens/UserPortal/People/People.spec.tsx similarity index 82% rename from src/screens/UserPortal/People/People.test.tsx rename to src/screens/UserPortal/People/People.spec.tsx index c978a0a5a3..11051538db 100644 --- a/src/screens/UserPortal/People/People.test.tsx +++ b/src/screens/UserPortal/People/People.spec.tsx @@ -13,6 +13,19 @@ import i18nForTest from 'utils/i18nForTest'; import { StaticMockLink } from 'utils/StaticMockLink'; import People from './People'; import userEvent from '@testing-library/user-event'; +import { vi } from 'vitest'; + +/** + * This file contains unit tests for the People component. + * + * The tests cover: + * - Proper rendering of the People screen and its elements. + * - Functionality of the search input and search button. + * - Correct behavior when switching between member and admin modes. + * - Integration with mocked GraphQL queries for testing data fetching. + * + * These tests use Vitest for test execution, MockedProvider for mocking GraphQL queries, and react-testing-library for rendering and interactions. + */ const MOCKS = [ { @@ -113,27 +126,30 @@ async function wait(ms = 100): Promise { }); } -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useParams: () => ({ orgId: '' }), -})); +vi.mock('react-router-dom', async () => { + const actual = await vi.importActual('react-router-dom'); + return { + ...actual, + useParams: () => ({ orgId: '' }), + }; +}); describe('Testing People Screen [User Portal]', () => { Object.defineProperty(window, 'matchMedia', { writable: true, - value: jest.fn().mockImplementation((query) => ({ + value: vi.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(), + addListener: vi.fn(), // Deprecated + removeListener: vi.fn(), // Deprecated + addEventListener: vi.fn(), + removeEventListener: vi.fn(), + dispatchEvent: vi.fn(), })), }); - test('Screen should be rendered properly', async () => { + it('Screen should be rendered properly', async () => { render( @@ -151,7 +167,7 @@ describe('Testing People Screen [User Portal]', () => { expect(screen.queryAllByText('Noble Mittal')).not.toBe([]); }); - test('Search works properly by pressing enter', async () => { + it('Search works properly by pressing enter', async () => { render( @@ -173,7 +189,7 @@ describe('Testing People Screen [User Portal]', () => { expect(screen.queryByText('Noble Mittal')).not.toBeInTheDocument(); }); - test('Search works properly by clicking search Btn', async () => { + it('Search works properly by clicking search Btn', async () => { render( @@ -199,7 +215,7 @@ describe('Testing People Screen [User Portal]', () => { expect(screen.queryByText('Noble Mittal')).not.toBeInTheDocument(); }); - test('Mode is changed to Admins', async () => { + it('Mode is changed to Admins', async () => { render( diff --git a/src/screens/UserPortal/Pledges/Pledges.tsx b/src/screens/UserPortal/Pledges/Pledges.tsx index 59802be507..33e8bf63c2 100644 --- a/src/screens/UserPortal/Pledges/Pledges.tsx +++ b/src/screens/UserPortal/Pledges/Pledges.tsx @@ -4,7 +4,7 @@ import styles from './Pledges.module.css'; import { useTranslation } from 'react-i18next'; import { Search, Sort, WarningAmberRounded } from '@mui/icons-material'; import useLocalStorage from 'utils/useLocalstorage'; -import type { InterfacePledgeInfo, InterfacePledger } from 'utils/interfaces'; +import type { InterfacePledgeInfo, InterfaceUserInfo } from 'utils/interfaces'; import { Unstable_Popup as BasePopup } from '@mui/base/Unstable_Popup'; import { type ApolloQueryResult, useQuery } from '@apollo/client'; import { USER_PLEDGES } from 'GraphQl/Queries/fundQueries'; @@ -81,7 +81,7 @@ const Pledges = (): JSX.Element => { } const [anchor, setAnchor] = useState(null); - const [extraUsers, setExtraUsers] = useState([]); + const [extraUsers, setExtraUsers] = useState([]); const [searchTerm, setSearchTerm] = useState(''); const [pledges, setPledges] = useState([]); const [pledge, setPledge] = useState(null); @@ -154,7 +154,7 @@ const Pledges = (): JSX.Element => { const handleClick = ( event: React.MouseEvent, - users: InterfacePledger[], + users: InterfaceUserInfo[], ): void => { setExtraUsers(users); setAnchor(anchor ? null : event.currentTarget); @@ -197,7 +197,7 @@ const Pledges = (): JSX.Element => {
{params.row.users .slice(0, 2) - .map((user: InterfacePledger, index: number) => ( + .map((user: InterfaceUserInfo, index: number) => (
{user.image ? ( { disablePortal className={`${styles.popup} ${extraUsers.length > 4 ? styles.popupExtra : ''}`} > - {extraUsers.map((user: InterfacePledger, index: number) => ( + {extraUsers.map((user: InterfaceUserInfo, index: number) => (
{ ); const homeEl = await screen.findByTestId('homeEl'); expect(homeEl).toBeInTheDocument(); + + const postCardContainers = screen.queryAllByTestId('postCardContainer'); + expect(postCardContainers).toHaveLength(0); }); }); diff --git a/src/screens/UserPortal/Posts/Posts.tsx b/src/screens/UserPortal/Posts/Posts.tsx index 256bb5f52f..ceb10c9b49 100644 --- a/src/screens/UserPortal/Posts/Posts.tsx +++ b/src/screens/UserPortal/Posts/Posts.tsx @@ -52,34 +52,16 @@ type Ad = { 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; - type: string; - organization: { - _id: string; - }; - mediaUrl: string; - endDate: string; - startDate: string; - - comments: InterfacePostComments; - likes: InterfacePostLikes; -} - -type AdvertisementsConnection = { - edges: { - node: InterfaceAdContent; - }[]; -}; type InterfacePostComments = { + id: string; creator: { - _id: string; + id: string; firstName: string; lastName: string; email: string; }; + likeCount: number; likedBy: { id: string; @@ -226,42 +208,24 @@ export default function home(): JSX.Element { comments, } = node; - const allLikes: any = []; - - likedBy.forEach((value: any) => { - const singleLike = { - firstName: value.firstName, - lastName: value.lastName, - id: value._id, - }; - allLikes.push(singleLike); - }); - - const postComments: any = []; - - comments.forEach((value: any) => { - const commentLikes: any = []; - value.likedBy.forEach((commentLike: any) => { - const singleLike = { - id: commentLike._id, - }; - commentLikes.push(singleLike); - }); - - const comment = { - id: value._id, - creator: { - firstName: value.creator.firstName, - lastName: value.creator.lastName, - id: value.creator._id, - email: value.creator.email, - }, - likeCount: value.likeCount, - likedBy: commentLikes, - text: value.text, - }; - postComments.push(comment); - }); + const allLikes: InterfacePostLikes = likedBy.map((value) => ({ + firstName: value.firstName, + lastName: value.lastName, + id: value._id, + })); + + const postComments: InterfacePostComments = comments?.map((value) => ({ + id: value.id, + creator: { + firstName: value.creator?.firstName ?? '', + lastName: value.creator?.lastName ?? '', + id: value.creator?.id ?? '', + email: value.creator?.email ?? '', + }, + likeCount: value.likeCount, + likedBy: value.likedBy?.map((like) => ({ id: like?.id ?? '' })) ?? [], + text: value.text, + })); const date = new Date(node.createdAt); const formattedDate = new Intl.DateTimeFormat('en-US', { @@ -311,7 +275,6 @@ export default function home(): JSX.Element { <>
-

{t('posts')}

{t('startPost')}
diff --git a/src/screens/UserPortal/Settings/Settings.module.css b/src/screens/UserPortal/Settings/Settings.module.css index 323aed3275..2558ea9f63 100644 --- a/src/screens/UserPortal/Settings/Settings.module.css +++ b/src/screens/UserPortal/Settings/Settings.module.css @@ -23,7 +23,11 @@ font-size: 1.2rem; font-weight: 600; } - +.scrollableCardBody { + max-height: min(220px, 50vh); + overflow-y: auto; + scroll-behavior: smooth; +} .cardHeader { padding: 1.25rem 1rem 1rem 1rem; border-bottom: 1px solid var(--bs-gray-200); @@ -36,6 +40,7 @@ padding: 1.25rem 1rem 1.5rem 1rem; display: flex; flex-direction: column; + overflow-y: scroll; } .cardLabel { @@ -137,6 +142,10 @@ padding: 2rem; } + .scrollableCardBody { + max-height: 40vh; + } + .contract, .expand { animation: none; diff --git a/src/screens/UserPortal/Settings/Settings.test.tsx b/src/screens/UserPortal/Settings/Settings.spec.tsx similarity index 70% rename from src/screens/UserPortal/Settings/Settings.test.tsx rename to src/screens/UserPortal/Settings/Settings.spec.tsx index 34aa3711bd..184789ab04 100644 --- a/src/screens/UserPortal/Settings/Settings.test.tsx +++ b/src/screens/UserPortal/Settings/Settings.spec.tsx @@ -1,5 +1,6 @@ -import React, { act } from 'react'; -import { fireEvent, render, screen } from '@testing-library/react'; +import React from 'react'; +import { describe, expect, beforeAll, vi } from 'vitest'; +import { render, screen, fireEvent, act } from '@testing-library/react'; import { MockedProvider } from '@apollo/react-testing'; import { I18nextProvider } from 'react-i18next'; import { UPDATE_USER_MUTATION } from 'GraphQl/Mutations/mutations'; @@ -11,7 +12,6 @@ import { StaticMockLink } from 'utils/StaticMockLink'; import Settings from './Settings'; import userEvent from '@testing-library/user-event'; import { CHECK_AUTH } from 'GraphQl/Queries/Queries'; - const MOCKS = [ { request: { @@ -63,6 +63,7 @@ const Mocks1 = [ countryCode: 'IN', line1: 'random', }, + eventsAttended: [{ _id: 'event1' }, { _id: 'event2' }], phone: { mobile: '+174567890', }, @@ -90,6 +91,7 @@ const Mocks2 = [ maritalStatus: '', educationGrade: '', employmentStatus: '', + eventsAttended: [], birthDate: '', address: { state: '', @@ -107,33 +109,6 @@ const Mocks2 = [ }, ]; -const mockMaritalStatusEnum = [ - { - value: 'SINGLE', - label: 'Single', - }, - { - value: 'ENGAGED', - label: 'Engaged', - }, - { - value: 'MARRIED', - label: 'Married', - }, - { - value: 'DIVORCED', - label: 'Divorced', - }, - { - value: 'WIDOWED', - label: 'Widowed', - }, - { - value: 'SEPARATED', - label: 'Separated', - }, -]; - const link = new StaticMockLink(MOCKS, true); const link1 = new StaticMockLink(Mocks1, true); const link2 = new StaticMockLink(Mocks2, true); @@ -145,31 +120,27 @@ const resizeWindow = (width: number): void => { async function wait(ms = 100): Promise { await act(async () => { - return new Promise((resolve) => { - setTimeout(resolve, ms); - }); + vi.advanceTimersByTime(ms); }); } describe('Testing Settings Screen [User Portal]', () => { - // Mock implementation of matchMedia beforeAll(() => { + vi.useFakeTimers(); Object.defineProperty(window, 'matchMedia', { writable: true, - value: jest.fn().mockImplementation((query) => ({ + value: vi.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(), + addEventListener: vi.fn(), + removeEventListener: vi.fn(), + dispatchEvent: vi.fn(), })), }); }); - test('Screen should be rendered properly', async () => { + it('Screen should be rendered properly', async () => { await act(async () => { render( @@ -189,7 +160,7 @@ describe('Testing Settings Screen [User Portal]', () => { expect(screen.queryAllByText('Settings')).not.toBe([]); }); - test('input works properly', async () => { + it('input works properly', async () => { await act(async () => { render( @@ -214,7 +185,7 @@ describe('Testing Settings Screen [User Portal]', () => { await wait(); userEvent.type(screen.getByTestId('inputPhoneNumber'), '1234567890'); await wait(); - userEvent.selectOptions(screen.getByTestId('inputGrade'), 'Grade 1'); + userEvent.selectOptions(screen.getByTestId('inputGrade'), 'Grade-1'); await wait(); userEvent.selectOptions(screen.getByTestId('inputEmpStatus'), 'Unemployed'); await wait(); @@ -243,10 +214,10 @@ describe('Testing Settings Screen [User Portal]', () => { const files = [imageFile]; userEvent.upload(fileInp, files); await wait(); - expect(screen.getAllByAltText('profile picture')[0]).toBeInTheDocument(); + expect(screen.getByTestId('profile-picture')).toBeInTheDocument(); }); - test('resetChangesBtn works properly', async () => { + it('resetChangesBtn works properly', async () => { await act(async () => { render( @@ -262,7 +233,8 @@ describe('Testing Settings Screen [User Portal]', () => { }); await wait(); - + userEvent.type(screen.getByTestId('inputAddress'), 'random'); + await wait(); userEvent.click(screen.getByTestId('resetChangesBtn')); await wait(); expect(screen.getByTestId('inputFirstName')).toHaveValue('John'); @@ -278,7 +250,7 @@ describe('Testing Settings Screen [User Portal]', () => { expect(screen.getByLabelText('Birth Date')).toHaveValue('2024-03-01'); }); - test('resetChangesBtn works properly when the details are empty', async () => { + it('resetChangesBtn works properly when the details are empty', async () => { await act(async () => { render( @@ -294,7 +266,8 @@ describe('Testing Settings Screen [User Portal]', () => { }); await wait(); - + userEvent.type(screen.getByTestId('inputAddress'), 'random'); + await wait(); userEvent.click(screen.getByTestId('resetChangesBtn')); await wait(); expect(screen.getByTestId('inputFirstName')).toHaveValue(''); @@ -310,7 +283,7 @@ describe('Testing Settings Screen [User Portal]', () => { expect(screen.getByLabelText('Birth Date')).toHaveValue(''); }); - test('sidebar', async () => { + it('sidebar', async () => { await act(async () => { render( @@ -335,7 +308,7 @@ describe('Testing Settings Screen [User Portal]', () => { act(() => openMenuBtn.click()); }); - test('Testing sidebar when the screen size is less than or equal to 820px', async () => { + it('Testing sidebar when the screen size is less than or equal to 820px', async () => { resizeWindow(800); await act(async () => { render( @@ -352,7 +325,6 @@ describe('Testing Settings Screen [User Portal]', () => { }); await wait(); - screen.debug(); const openMenuBtn = screen.queryByTestId('openMenu'); @@ -371,4 +343,103 @@ describe('Testing Settings Screen [User Portal]', () => { act(() => closeMenuBtn.click()); } }); + + it('renders events attended card correctly', async () => { + render( + + + + + + + + + , + ); + await wait(); + // Check if the card title is rendered + expect(screen.getByText('Events Attended')).toBeInTheDocument(); + await wait(1000); + // Check for empty state immediately + expect(screen.getByText('No Events Attended')).toBeInTheDocument(); + }); + + it('renders events attended card correctly with events', async () => { + const mockEventsAttended = [ + { _id: '1', title: 'Event 1' }, + { _id: '2', title: 'Event 2' }, + ]; + + const MocksWithEvents = [ + { + ...Mocks1[0], + result: { + data: { + checkAuth: { + ...Mocks1[0].result.data.checkAuth, + eventsAttended: mockEventsAttended, + }, + }, + }, + }, + ]; + + const linkWithEvents = new StaticMockLink(MocksWithEvents, true); + + render( + + + + + + + + + , + ); + + await wait(1000); + + expect(screen.getByText('Events Attended')).toBeInTheDocument(); + const eventsCards = screen.getAllByTestId('usereventsCard'); + expect(eventsCards.length).toBe(2); + + eventsCards.forEach((card) => { + expect(card).toBeInTheDocument(); + expect(card.children.length).toBe(1); + }); + }); +}); + +it('prevents selecting future dates for birth date', async () => { + await act(async () => { + render( + + + + + + + + + , + ); + }); + + const birthDateInput = screen.getByLabelText( + 'Birth Date', + ) as HTMLInputElement; + const today = new Date().toISOString().split('T')[0]; + const futureDate = new Date(); + futureDate.setFullYear(futureDate.getFullYear() + 100); + const futureDateString = futureDate.toISOString().split('T')[0]; + + // Trying future date + fireEvent.change(birthDateInput, { target: { value: futureDateString } }); + // Checking if value is not updated to future date + expect(birthDateInput.value).not.toBe(futureDateString); + + // Checking if value set correctly + fireEvent.change(birthDateInput, { target: { value: today } }); + expect(birthDateInput.value).toBe(today); }); diff --git a/src/screens/UserPortal/Settings/Settings.tsx b/src/screens/UserPortal/Settings/Settings.tsx index 8b80f8ea1d..385c3d639e 100644 --- a/src/screens/UserPortal/Settings/Settings.tsx +++ b/src/screens/UserPortal/Settings/Settings.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useRef, useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import styles from './Settings.module.css'; import { Button, Card, Col, Form, Row } from 'react-bootstrap'; @@ -10,17 +10,19 @@ import { toast } from 'react-toastify'; import { CHECK_AUTH } from 'GraphQl/Queries/Queries'; import useLocalStorage from 'utils/useLocalstorage'; import { - countryOptions, educationGradeEnum, employmentStatusEnum, genderEnum, maritalStatusEnum, } from 'utils/formEnumFields'; -import UserProfile from 'components/UserProfileSettings/UserProfile'; import DeleteUser from 'components/UserProfileSettings/DeleteUser'; import OtherSettings from 'components/UserProfileSettings/OtherSettings'; import UserSidebar from 'components/UserPortal/UserSidebar/UserSidebar'; import ProfileDropdown from 'components/ProfileDropdown/ProfileDropdown'; +import Avatar from 'components/Avatar/Avatar'; +import type { InterfaceEvent } from 'components/EventManagement/EventAttendance/InterfaceEvents'; +import { EventsAttendedByUser } from 'components/UserPortal/UserProfile/EventsAttendedByUser'; +import UserAddressFields from 'components/UserPortal/UserProfile/UserAddressFields'; /** * The Settings component allows users to view and update their profile settings. @@ -33,6 +35,7 @@ export default function settings(): JSX.Element { keyPrefix: 'settings', }); const { t: tCommon } = useTranslation('common'); + const [isUpdated, setisUpdated] = useState(false); const [hideDrawer, setHideDrawer] = useState(null); /** @@ -56,8 +59,7 @@ 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] = useState({ + const [userDetails, setUserDetails] = React.useState({ firstName: '', lastName: '', createdAt: '', @@ -72,6 +74,7 @@ export default function settings(): JSX.Element { state: '', country: '', image: '', + eventsAttended: [] as InterfaceEvent[], }); /** @@ -88,6 +91,8 @@ export default function settings(): JSX.Element { * This function sends a mutation request to update the user details * and reloads the page on success. */ + + /*istanbul ignore next*/ const handleUpdateUserDetails = async (): Promise => { try { let updatedUserDetails = { ...userDetails }; @@ -109,6 +114,7 @@ export default function settings(): JSX.Element { setItem('name', userFullName); } } catch (error: unknown) { + /*istanbul ignore next*/ errorHandler(t, error); } }; @@ -120,6 +126,20 @@ export default function settings(): JSX.Element { * @param value - The new value for the field. */ const handleFieldChange = (fieldName: string, value: string): void => { + // If the field is 'birthDate', validate the date + if (fieldName === 'birthDate') { + const today = new Date(); + const selectedDate = new Date(value); + + // Prevent updating the state if the selected date is in the future + if (selectedDate > today) { + console.error('Future dates are not allowed for the birth date.'); + return; // Exit without updating the state + } + } + + // Update state if the value passes validation + setisUpdated(true); setUserDetails((prevState) => ({ ...prevState, [fieldName]: value, @@ -130,6 +150,7 @@ 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) { (fileInputRef.current as HTMLInputElement).click(); } @@ -139,6 +160,7 @@ export default function settings(): JSX.Element { * Resets the user details to the values fetched from the server. */ const handleResetChanges = (): void => { + setisUpdated(false); /* istanbul ignore next */ if (data) { const { @@ -188,6 +210,7 @@ export default function settings(): JSX.Element { maritalStatus, address, image, + eventsAttended, } = data.checkAuth; setUserDetails({ @@ -204,12 +227,12 @@ export default function settings(): JSX.Element { address: address?.line1 || '', state: address?.state || '', country: address?.countryCode || '', + eventsAttended, image, }); originalImageState.current = image; } }, [data]); - return ( <> {hideDrawer ? ( @@ -250,17 +273,8 @@ export default function settings(): JSX.Element {
- - - - - +

{tCommon('settings')}

+
@@ -270,6 +284,70 @@ export default function settings(): JSX.Element {
+ +
+
+ {userDetails?.image ? ( + User + ) : ( + + )} + e.key === 'Enter' && handleImageUpload() + } + /> +
+
+ , + ): Promise => { + const file = e.target?.files?.[0]; + if (file) { + const image = await convertToBase64(file); + setUserDetails({ ...userDetails, image }); + } + } + } + style={{ display: 'none' }} + /> + {genderEnum.map((g) => ( ))} @@ -369,49 +447,6 @@ export default function settings(): JSX.Element { data-testid="inputPhoneNumber" /> - - - {tCommon('displayImage')} - -
- - , - ): Promise => { - const target = e.target as HTMLInputElement; - const file = target.files && target.files[0]; - if (file) { - const image = await convertToBase64(file); - setUserDetails({ ...userDetails, image }); - } - } - } - style={{ display: 'none' }} - /> -
- -
- + + - {t(grade.label)} + {grade.label} ))} - - - {t(status.label)} + {status.label} ))} @@ -516,109 +552,46 @@ export default function settings(): JSX.Element { key={status.value.toLowerCase()} value={status.value} > - {t(status.label)} + {status.label} ))} - - - - {tCommon('address')} - - - handleFieldChange('address', e.target.value) - } - className={`${styles.cardControl}`} - data-testid="inputAddress" - /> - - - - {t('state')} - - - handleFieldChange('state', e.target.value) - } - className={`${styles.cardControl}`} - data-testid="inputState" - /> - - - + {isUpdated && ( +
+ + - -
+ {tCommon('saveChanges')} + +
+ )} - @@ -627,6 +600,7 @@ export default function settings(): JSX.Element { +
diff --git a/src/screens/UserPortal/UserScreen/UserScreen.test.tsx b/src/screens/UserPortal/UserScreen/UserScreen.spec.tsx similarity index 71% rename from src/screens/UserPortal/UserScreen/UserScreen.test.tsx rename to src/screens/UserPortal/UserScreen/UserScreen.spec.tsx index 96ee9767f2..65c5e6a650 100644 --- a/src/screens/UserPortal/UserScreen/UserScreen.test.tsx +++ b/src/screens/UserPortal/UserScreen/UserScreen.spec.tsx @@ -1,24 +1,40 @@ +/** + * This file contains unit tests for the UserScreen component. + * + * The tests cover: + * - Rendering of the correct title based on the location. + * - Functionality of the LeftDrawer component. + * - Behavior when the orgId is undefined. + * + * These tests use Vitest for test execution and MockedProvider for mocking GraphQL queries. + */ + import React from 'react'; +import { render, screen, fireEvent } from '@testing-library/react'; +import { describe, it, vi, beforeEach, expect } from 'vitest'; import { MockedProvider } from '@apollo/react-testing'; -import { fireEvent, render, screen } from '@testing-library/react'; import { I18nextProvider } from 'react-i18next'; -import 'jest-location-mock'; import { Provider } from 'react-redux'; -import { BrowserRouter } from 'react-router-dom'; +import { BrowserRouter, useNavigate } from 'react-router-dom'; import { store } from 'state/store'; import i18nForTest from 'utils/i18nForTest'; import UserScreen from './UserScreen'; import { ORGANIZATIONS_LIST } from 'GraphQl/Queries/Queries'; import { StaticMockLink } from 'utils/StaticMockLink'; +import '@testing-library/jest-dom'; 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 }), -})); +vi.mock('react-router-dom', async () => { + const actual = await vi.importActual('react-router-dom'); + return { + ...actual, + useParams: () => ({ orgId: mockID }), + useLocation: () => ({ pathname: mockLocation }), + useNavigate: vi.fn(), // Mock only the necessary parts + }; +}); const MOCKS = [ { @@ -72,8 +88,13 @@ const clickToggleMenuBtn = (toggleButton: HTMLElement): void => { fireEvent.click(toggleButton); }; -describe('Testing LeftDrawer in OrganizationScreen', () => { - test('renders the correct title based on the titleKey for posts', () => { +describe('UserScreen tests with LeftDrawer functionality', () => { + beforeEach(() => { + mockID = '123'; + mockLocation = '/user/organization/123'; + }); + + it('renders the correct title for posts', () => { render( @@ -87,10 +108,10 @@ describe('Testing LeftDrawer in OrganizationScreen', () => { ); const titleElement = screen.getByRole('heading', { level: 1 }); - expect(titleElement).toHaveTextContent(''); + expect(titleElement).toHaveTextContent('Posts'); }); - test('renders the correct title based on the titleKey', () => { + it('renders the correct title for people', () => { mockLocation = '/user/people/123'; render( @@ -109,7 +130,7 @@ describe('Testing LeftDrawer in OrganizationScreen', () => { expect(titleElement).toHaveTextContent('People'); }); - test('Testing LeftDrawer in page functionality', async () => { + it('toggles LeftDrawer correctly based on window size and user interaction', () => { render( @@ -121,25 +142,30 @@ describe('Testing LeftDrawer in OrganizationScreen', () => { , ); + const toggleButton = screen.getByTestId('closeMenu') as HTMLElement; const icon = toggleButton.querySelector('i'); - // Resize window to a smaller width + // Resize to small screen and check toggle state resizeWindow(800); clickToggleMenuBtn(toggleButton); expect(icon).toHaveClass('fa fa-angle-double-left'); - // Resize window back to a larger width + // Resize to large screen and check toggle state resizeWindow(1000); clickToggleMenuBtn(toggleButton); expect(icon).toHaveClass('fa fa-angle-double-right'); + // Check state on re-click clickToggleMenuBtn(toggleButton); expect(icon).toHaveClass('fa fa-angle-double-left'); }); - test('should be redirected to / if orgId is undefined', async () => { + it('redirects to root when orgId is undefined', () => { mockID = undefined; + const navigate = vi.fn(); + vi.spyOn({ useNavigate }, 'useNavigate').mockReturnValue(navigate); + render( @@ -151,6 +177,7 @@ describe('Testing LeftDrawer in OrganizationScreen', () => { , ); + expect(window.location.pathname).toEqual('/'); }); }); diff --git a/src/screens/UserPortal/UserScreen/UserScreen.tsx b/src/screens/UserPortal/UserScreen/UserScreen.tsx index 8543803933..39b422858f 100644 --- a/src/screens/UserPortal/UserScreen/UserScreen.tsx +++ b/src/screens/UserPortal/UserScreen/UserScreen.tsx @@ -19,6 +19,8 @@ const map: InterfaceMapType = { donate: 'donate', campaigns: 'userCampaigns', pledges: 'userPledges', + volunteer: 'userVolunteer', + leaveorg: 'leaveOrganization', }; /** @@ -130,7 +132,7 @@ const UserScreen = (): JSX.Element => { >
-

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

+

{t('title')}

diff --git a/src/screens/UserPortal/Volunteer/Actions/Actions.mocks.ts b/src/screens/UserPortal/Volunteer/Actions/Actions.mocks.ts new file mode 100644 index 0000000000..5162134c65 --- /dev/null +++ b/src/screens/UserPortal/Volunteer/Actions/Actions.mocks.ts @@ -0,0 +1,268 @@ +import { ACTION_ITEMS_BY_USER } from 'GraphQl/Queries/ActionItemQueries'; + +const action1 = { + _id: 'actionId1', + assignee: { + _id: 'volunteerId1', + user: { + _id: 'userId', + firstName: 'Teresa', + lastName: 'Bradley', + image: null, + }, + }, + assigneeGroup: null, + assigneeType: 'EventVolunteer', + assigner: { + _id: 'userId1', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + }, + actionItemCategory: { + _id: 'categoryId1', + name: 'Category 1', + }, + preCompletionNotes: '', + postCompletionNotes: '', + assignmentDate: '2024-10-25', + dueDate: '2025-10-25', + completionDate: '2024-11-01', + isCompleted: false, + event: { + _id: 'eventId1', + title: 'Event 1', + }, + creator: { + _id: 'userId1', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + allottedHours: 8, +}; + +const action2 = { + _id: 'actionId2', + assignee: null, + assigneeGroup: { + _id: 'groupId1', + name: 'Group 1', + }, + assigneeType: 'EventVolunteerGroup', + assigner: { + _id: 'userId1', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + }, + actionItemCategory: { + _id: 'categoryId2', + name: 'Category 2', + }, + preCompletionNotes: '', + postCompletionNotes: '', + assignmentDate: '2024-10-25', + dueDate: '2025-10-26', + completionDate: '2024-11-01', + isCompleted: false, + event: { + _id: 'eventId1', + title: 'Event 1', + }, + creator: { + _id: 'userId1', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + allottedHours: 8, +}; + +const action3 = { + _id: 'actionId3', + assignee: { + _id: 'volunteerId3', + user: { + _id: 'userId', + firstName: 'Teresa', + lastName: 'Bradley', + image: 'img-url', + }, + }, + assigneeGroup: null, + assigneeType: 'EventVolunteer', + assigner: { + _id: 'userId1', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + }, + actionItemCategory: { + _id: 'categoryId3', + name: 'Category 3', + }, + preCompletionNotes: '', + postCompletionNotes: '', + assignmentDate: '2024-10-25', + dueDate: '2024-10-27', + completionDate: '2024-11-01', + isCompleted: true, + event: { + _id: 'eventId2', + title: 'Event 2', + }, + creator: { + _id: 'userId1', + firstName: 'Wilt', + lastName: 'Shepherd', + }, + allottedHours: null, +}; + +export const MOCKS = [ + { + request: { + query: ACTION_ITEMS_BY_USER, + variables: { + userId: 'userId', + orderBy: null, + where: { + orgId: 'orgId', + assigneeName: '', + }, + }, + }, + result: { + data: { + actionItemsByUser: [action1, action2, action3], + }, + }, + }, + { + request: { + query: ACTION_ITEMS_BY_USER, + variables: { + userId: 'userId', + orderBy: 'dueDate_DESC', + where: { + orgId: 'orgId', + assigneeName: '', + }, + }, + }, + result: { + data: { + actionItemsByUser: [action2, action1], + }, + }, + }, + { + request: { + query: ACTION_ITEMS_BY_USER, + variables: { + userId: 'userId', + orderBy: 'dueDate_ASC', + where: { + orgId: 'orgId', + assigneeName: '', + }, + }, + }, + result: { + data: { + actionItemsByUser: [action1, action2], + }, + }, + }, + { + request: { + query: ACTION_ITEMS_BY_USER, + variables: { + userId: 'userId', + orderBy: null, + where: { + orgId: 'orgId', + assigneeName: '1', + }, + }, + }, + result: { + data: { + actionItemsByUser: [action2], + }, + }, + }, + { + request: { + query: ACTION_ITEMS_BY_USER, + variables: { + userId: 'userId', + orderBy: null, + where: { + orgId: 'orgId', + categoryName: '', + }, + }, + }, + result: { + data: { + actionItemsByUser: [action1, action2], + }, + }, + }, + { + request: { + query: ACTION_ITEMS_BY_USER, + variables: { + userId: 'userId', + orderBy: null, + where: { + orgId: 'orgId', + categoryName: '1', + }, + }, + }, + result: { + data: { + actionItemsByUser: [action1], + }, + }, + }, +]; + +export const EMPTY_MOCKS = [ + { + request: { + query: ACTION_ITEMS_BY_USER, + variables: { + userId: 'userId', + orderBy: null, + where: { + orgId: 'orgId', + assigneeName: '', + }, + }, + }, + result: { + data: { + actionItemsByUser: [], + }, + }, + }, +]; + +export const ERROR_MOCKS = [ + { + request: { + query: ACTION_ITEMS_BY_USER, + variables: { + userId: 'userId', + orderBy: null, + where: { + orgId: 'orgId', + assigneeName: '', + }, + }, + }, + error: new Error('Mock Graphql ACTION_ITEMS_BY_USER Error'), + }, +]; diff --git a/src/screens/UserPortal/Volunteer/Actions/Actions.spec.tsx b/src/screens/UserPortal/Volunteer/Actions/Actions.spec.tsx new file mode 100644 index 0000000000..dea26c5fe1 --- /dev/null +++ b/src/screens/UserPortal/Volunteer/Actions/Actions.spec.tsx @@ -0,0 +1,264 @@ +/** + * Unit tests for the Actions component. + * + * This file contains tests for the Actions component to ensure it behaves as expected + * under various scenarios. + */ + +import React, { act } 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 { 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 i18n from 'utils/i18nForTest'; +import Actions from './Actions'; +import type { ApolloLink } from '@apollo/client'; +import { MOCKS, EMPTY_MOCKS, ERROR_MOCKS } from './Actions.mocks'; +import useLocalStorage from 'utils/useLocalstorage'; +import { describe, it, beforeAll, beforeEach, afterAll, vi } from 'vitest'; + +const { setItem } = useLocalStorage(); + +const link1 = new StaticMockLink(MOCKS); +const link2 = new StaticMockLink(ERROR_MOCKS); +const link3 = new StaticMockLink(EMPTY_MOCKS); + +const t = { + ...JSON.parse( + JSON.stringify( + i18n.getDataByLanguage('en')?.translation.organizationActionItems ?? {}, + ), + ), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.common ?? {})), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.errors ?? {})), +}; + +const debounceWait = async (ms = 300): Promise => { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +}; +const mockNavigate = vi.fn(); + +const expectVitestToBeInTheDocument = (element: HTMLElement): void => { + expect(element).toBeInTheDocument(); +}; + +const expectElementToHaveTextContent = ( + element: HTMLElement, + text: string, +): void => { + expect(element).toHaveTextContent(text); +}; + +const renderActions = (link: ApolloLink): RenderResult => { + return render( + + + + + + + } /> +
} + /> + + + + + + , + ); +}; + +describe('Testing Actions Screen', () => { + beforeAll(() => { + vi.mock('react-router-dom', async () => { + const actual = await vi.importActual('react-router-dom'); // Import the actual implementation + return { + ...actual, + useNavigate: () => mockNavigate, // Replace useNavigate with the mock + }; + }); + }); + + beforeEach(() => { + setItem('userId', 'userId'); + }); + + afterAll(() => { + vi.restoreAllMocks(); + }); + + it('should redirect to fallback URL if URL params are undefined', async () => { + setItem('userId', null); + render( + + + + + + } /> +
} + /> + + + + +
, + ); + + await waitFor(() => { + expectVitestToBeInTheDocument(screen.getByTestId('paramsError')); + }); + }); + + it('should render Actions screen', async () => { + renderActions(link1); + await waitFor(async () => { + const searchInput = await screen.findByTestId('searchBy'); + expectVitestToBeInTheDocument(searchInput); + + const assigneeName = await screen.findAllByTestId('assigneeName'); + expectElementToHaveTextContent(assigneeName[0], 'Teresa Bradley'); + }); + }); + + it('Check Sorting Functionality', async () => { + renderActions(link1); + + const searchInput = await screen.findByTestId('searchBy'); + expectVitestToBeInTheDocument(searchInput); + + let sortBtn = await screen.findByTestId('sort'); + expectVitestToBeInTheDocument(sortBtn); + + // Sort by dueDate_DESC + fireEvent.click(sortBtn); + const dueDateDESC = await screen.findByTestId('dueDate_DESC'); + expectVitestToBeInTheDocument(dueDateDESC); + fireEvent.click(dueDateDESC); + + await waitFor(() => { + const assigneeName = screen.getAllByTestId('assigneeName'); + expectElementToHaveTextContent(assigneeName[0], 'Group 1'); + }); + + // Sort by dueDate_ASC + sortBtn = await screen.findByTestId('sort'); + expectVitestToBeInTheDocument(sortBtn); + fireEvent.click(sortBtn); + const dueDateASC = await screen.findByTestId('dueDate_ASC'); + expectVitestToBeInTheDocument(dueDateASC); + fireEvent.click(dueDateASC); + + await waitFor(() => { + const assigneeName = screen.getAllByTestId('assigneeName'); + expectElementToHaveTextContent(assigneeName[0], 'Teresa Bradley'); + }); + }); + + it('Search by Assignee name', async () => { + renderActions(link1); + await waitFor(async () => { + const searchInput = await screen.findByTestId('searchBy'); + expectVitestToBeInTheDocument(searchInput); + + const searchToggle = await screen.findByTestId('searchByToggle'); + expectVitestToBeInTheDocument(searchToggle); + userEvent.click(searchToggle); + + const searchByAssignee = await screen.findByTestId('assignee'); + expectVitestToBeInTheDocument(searchByAssignee); + userEvent.click(searchByAssignee); + + userEvent.type(searchInput, '1'); + }); + await debounceWait(); + + await waitFor(async () => { + const assigneeName = await screen.findAllByTestId('assigneeName'); + expectElementToHaveTextContent(assigneeName[0], 'Group 1'); + }); + }); + + it('Search by Category name', async () => { + renderActions(link1); + await waitFor(async () => { + const searchInput = await screen.findByTestId('searchBy'); + expectVitestToBeInTheDocument(searchInput); + + const searchToggle = await screen.findByTestId('searchByToggle'); + expectVitestToBeInTheDocument(searchToggle); + userEvent.click(searchToggle); + + const searchByCategory = await screen.findByTestId('category'); + expectVitestToBeInTheDocument(searchByCategory); + userEvent.click(searchByCategory); + + userEvent.type(searchInput, '1'); + }); + await debounceWait(); + + await waitFor(() => { + const assigneeName = screen.getAllByTestId('assigneeName'); + expectElementToHaveTextContent(assigneeName[0], 'Teresa Bradley'); + }); + }); + + it('should render screen with No Actions', async () => { + renderActions(link3); + + await waitFor(() => { + expectVitestToBeInTheDocument(screen.getByTestId('searchBy')); + expectVitestToBeInTheDocument(screen.getByText(t.noActionItems)); + }); + }); + + it('Error while fetching Actions data', async () => { + renderActions(link2); + + await waitFor(() => { + expectVitestToBeInTheDocument(screen.getByTestId('errorMsg')); + }); + }); + + it('Open and close ItemUpdateStatusModal', async () => { + renderActions(link1); + + const checkbox = await screen.findAllByTestId('statusCheckbox'); + userEvent.click(checkbox[0]); + + await waitFor(async () => { + const element = await screen.findByText(t.actionItemStatus); // Resolve the promise + expectVitestToBeInTheDocument(element); // Now assert the resolved element + }); + userEvent.click(await screen.findByTestId('modalCloseBtn')); + }); + + it('Open and close ItemViewModal', async () => { + renderActions(link1); + + const viewItemBtn = await screen.findAllByTestId('viewItemBtn'); + userEvent.click(viewItemBtn[0]); + + await waitFor(() => { + expectVitestToBeInTheDocument(screen.getByText(t.actionItemDetails)); + }); + + userEvent.click(await screen.findByTestId('modalCloseBtn')); + }); +}); diff --git a/src/screens/UserPortal/Volunteer/Actions/Actions.tsx b/src/screens/UserPortal/Volunteer/Actions/Actions.tsx new file mode 100644 index 0000000000..9bc23969c2 --- /dev/null +++ b/src/screens/UserPortal/Volunteer/Actions/Actions.tsx @@ -0,0 +1,471 @@ +import React, { useCallback, useMemo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Button, Dropdown, Form } from 'react-bootstrap'; +import { Navigate, useParams } from 'react-router-dom'; + +import { Circle, Search, Sort, WarningAmberRounded } from '@mui/icons-material'; +import dayjs from 'dayjs'; + +import { useQuery } from '@apollo/client'; + +import type { InterfaceActionItemInfo } from 'utils/interfaces'; +import styles from '../../../../style/app.module.css'; +import Loader from 'components/Loader/Loader'; +import { + DataGrid, + type GridCellParams, + type GridColDef, +} from '@mui/x-data-grid'; +import { Chip, debounce, Stack } from '@mui/material'; +import ItemViewModal from 'screens/OrganizationActionItems/ItemViewModal'; +import Avatar from 'components/Avatar/Avatar'; +import ItemUpdateStatusModal from 'screens/OrganizationActionItems/ItemUpdateStatusModal'; +import { ACTION_ITEMS_BY_USER } from 'GraphQl/Queries/ActionItemQueries'; +import useLocalStorage from 'utils/useLocalstorage'; + +enum ModalState { + VIEW = 'view', + STATUS = 'status', +} + +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', + }, +}; + +/** + * Component for managing and displaying action items within an organization. + * + * This component allows users to view, filter, sort, and create action items. It also handles fetching and displaying related data such as action item categories and members. + * + * @returns The rendered component. + */ +function actions(): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'organizationActionItems', + }); + const { t: tCommon } = useTranslation('common'); + const { t: tErrors } = useTranslation('errors'); + + // Get the organization ID from URL parameters + const { orgId } = useParams(); + const { getItem } = useLocalStorage(); + const userId = getItem('userId'); + + if (!orgId || !userId) { + return ; + } + + const [actionItem, setActionItem] = useState( + null, + ); + const [searchValue, setSearchValue] = useState(''); + const [searchTerm, setSearchTerm] = useState(''); + const [sortBy, setSortBy] = useState<'dueDate_ASC' | 'dueDate_DESC' | null>( + null, + ); + const [searchBy, setSearchBy] = useState<'assignee' | 'category'>('assignee'); + const [modalState, setModalState] = useState<{ + [key in ModalState]: boolean; + }>({ + [ModalState.VIEW]: false, + [ModalState.STATUS]: false, + }); + + const debouncedSearch = useMemo( + () => debounce((value: string) => setSearchTerm(value), 300), + [], + ); + + const openModal = (modal: ModalState): void => + setModalState((prevState) => ({ ...prevState, [modal]: true })); + + const closeModal = (modal: ModalState): void => + setModalState((prevState) => ({ ...prevState, [modal]: false })); + + const handleModalClick = useCallback( + (actionItem: InterfaceActionItemInfo | null, modal: ModalState): void => { + setActionItem(actionItem); + openModal(modal); + }, + [openModal], + ); + + /** + * Query to fetch action items for the organization based on filters and sorting. + */ + const { + data: actionItemsData, + loading: actionItemsLoading, + error: actionItemsError, + refetch: actionItemsRefetch, + }: { + data?: { + actionItemsByUser: InterfaceActionItemInfo[]; + }; + loading: boolean; + error?: Error | undefined; + refetch: () => void; + } = useQuery(ACTION_ITEMS_BY_USER, { + variables: { + userId, + orderBy: sortBy, + where: { + orgId, + assigneeName: searchBy === 'assignee' ? searchTerm : undefined, + categoryName: searchBy === 'category' ? searchTerm : undefined, + }, + }, + }); + + const actionItems = useMemo( + () => actionItemsData?.actionItemsByUser || [], + [actionItemsData], + ); + + if (actionItemsLoading) { + return ; + } + + if (actionItemsError) { + return ( +
+ +
+ {tErrors('errorLoading', { entity: 'Action Items' })} +
+
+ ); + } + + const columns: GridColDef[] = [ + { + field: 'assignee', + headerName: 'Assignee', + flex: 1, + align: 'left', + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + const { _id, firstName, lastName, image } = + params.row.assignee?.user || {}; + + return ( + <> + {params.row.assigneeType === 'EventVolunteer' ? ( + <> +
+ {image ? ( + Assignee + ) : ( +
+ +
+ )} + {firstName + ' ' + lastName} +
+ + ) : ( + <> +
+
+ +
+ {params.row.assigneeGroup?.name as string} +
+ + )} + + ); + }, + }, + { + field: 'itemCategory', + headerName: 'Item Category', + flex: 1, + align: 'center', + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + return ( +
+ {params.row.actionItemCategory?.name} +
+ ); + }, + }, + { + field: 'status', + headerName: 'Status', + flex: 1, + align: 'center', + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + return ( + } + label={params.row.isCompleted ? 'Completed' : 'Pending'} + variant="outlined" + color="primary" + className={`${styles.chip} ${params.row.isCompleted ? styles.active : styles.pending}`} + /> + ); + }, + }, + { + field: 'allottedHours', + headerName: 'Allotted Hours', + align: 'center', + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + flex: 1, + renderCell: (params: GridCellParams) => { + return ( +
+ {params.row.allottedHours ?? '-'} +
+ ); + }, + }, + { + field: 'dueDate', + headerName: 'Due Date', + align: 'center', + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + flex: 1, + renderCell: (params: GridCellParams) => { + return ( +
+ {dayjs(params.row.dueDate).format('DD/MM/YYYY')} +
+ ); + }, + }, + { + field: 'options', + headerName: 'Options', + align: 'center', + flex: 1, + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + return ( + <> + + + ); + }, + }, + { + field: 'completed', + headerName: 'Completed', + align: 'center', + flex: 1, + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + return ( +
+ handleModalClick(params.row, ModalState.STATUS)} + /> +
+ ); + }, + }, + ]; + + return ( +
+ {/* Header with search, filter and Create Button */} +
+
+ { + setSearchValue(e.target.value); + debouncedSearch(e.target.value); + }} + data-testid="searchBy" + /> + +
+
+
+ + + + {tCommon('searchBy', { item: '' })} + + + setSearchBy('assignee')} + data-testid="assignee" + > + {t('assignee')} + + setSearchBy('category')} + data-testid="category" + > + {t('category')} + + + + + + + {tCommon('sort')} + + + setSortBy('dueDate_DESC')} + data-testid="dueDate_DESC" + > + {t('latestDueDate')} + + setSortBy('dueDate_ASC')} + data-testid="dueDate_ASC" + > + {t('earliestDueDate')} + + + +
+
+
+ + {/* Table with Action Items */} + row._id} + slots={{ + noRowsOverlay: () => ( + + {t('noActionItems')} + + ), + }} + sx={dataGridStyle} + getRowClassName={() => `${styles.rowBackground}`} + autoHeight + rowHeight={65} + rows={actionItems} + columns={columns} + isRowSelectable={() => false} + /> + + {/* View Modal */} + {actionItem && ( + <> + closeModal(ModalState.VIEW)} + item={actionItem} + /> + + closeModal(ModalState.STATUS)} + actionItemsRefetch={actionItemsRefetch} + /> + + )} +
+ ); +} + +export default actions; diff --git a/src/screens/UserPortal/Volunteer/Groups/GroupModal.test.tsx b/src/screens/UserPortal/Volunteer/Groups/GroupModal.test.tsx new file mode 100644 index 0000000000..1d83d9a872 --- /dev/null +++ b/src/screens/UserPortal/Volunteer/Groups/GroupModal.test.tsx @@ -0,0 +1,308 @@ +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 { 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 i18n from 'utils/i18nForTest'; +import { MOCKS, UPDATE_ERROR_MOCKS } from './Groups.mocks'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import { toast } from 'react-toastify'; +import type { InterfaceGroupModal } from './GroupModal'; +import GroupModal from './GroupModal'; +import userEvent from '@testing-library/user-event'; + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + error: jest.fn(), + }, +})); + +const link1 = new StaticMockLink(MOCKS); +const link2 = new StaticMockLink(UPDATE_ERROR_MOCKS); +const t = { + ...JSON.parse( + JSON.stringify( + i18n.getDataByLanguage('en')?.translation.eventVolunteers ?? {}, + ), + ), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.common ?? {})), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.errors ?? {})), +}; + +const itemProps: InterfaceGroupModal[] = [ + { + isOpen: true, + hide: jest.fn(), + eventId: 'eventId', + refetchGroups: jest.fn(), + group: { + _id: 'groupId', + name: 'Group 1', + description: 'desc', + volunteersRequired: null, + createdAt: '2024-10-25T16:16:32.978Z', + creator: { + _id: 'creatorId1', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + }, + leader: { + _id: 'userId', + firstName: 'Teresa', + lastName: 'Bradley', + image: 'img-url', + }, + volunteers: [ + { + _id: 'volunteerId1', + user: { + _id: 'userId', + firstName: 'Teresa', + lastName: 'Bradley', + image: null, + }, + }, + ], + assignments: [], + event: { + _id: 'eventId', + }, + }, + }, + { + isOpen: true, + hide: jest.fn(), + eventId: 'eventId', + refetchGroups: jest.fn(), + group: { + _id: 'groupId', + name: 'Group 1', + description: null, + volunteersRequired: null, + createdAt: '2024-10-25T16:16:32.978Z', + creator: { + _id: 'creatorId1', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + }, + leader: { + _id: 'userId', + firstName: 'Teresa', + lastName: 'Bradley', + image: 'img-url', + }, + volunteers: [], + assignments: [], + event: { + _id: 'eventId', + }, + }, + }, +]; + +const renderGroupModal = ( + link: ApolloLink, + props: InterfaceGroupModal, +): RenderResult => { + return render( + + + + + + + + + + + , + ); +}; + +describe('Testing GroupModal', () => { + it('GroupModal -> Requests -> Accept', async () => { + renderGroupModal(link1, itemProps[0]); + expect(screen.getByText(t.manageGroup)).toBeInTheDocument(); + + const requestsBtn = screen.getByText(t.requests); + expect(requestsBtn).toBeInTheDocument(); + userEvent.click(requestsBtn); + + const userName = await screen.findAllByTestId('userName'); + expect(userName).toHaveLength(2); + expect(userName[0]).toHaveTextContent('John Doe'); + expect(userName[1]).toHaveTextContent('Teresa Bradley'); + + const acceptBtn = screen.getAllByTestId('acceptBtn'); + expect(acceptBtn).toHaveLength(2); + userEvent.click(acceptBtn[0]); + await waitFor(() => { + expect(toast.success).toHaveBeenCalledWith(t.requestAccepted); + }); + }); + + it('GroupModal -> Requests -> Reject', async () => { + renderGroupModal(link1, itemProps[0]); + expect(screen.getByText(t.manageGroup)).toBeInTheDocument(); + + const requestsBtn = screen.getByText(t.requests); + expect(requestsBtn).toBeInTheDocument(); + userEvent.click(requestsBtn); + + const userName = await screen.findAllByTestId('userName'); + expect(userName).toHaveLength(2); + expect(userName[0]).toHaveTextContent('John Doe'); + expect(userName[1]).toHaveTextContent('Teresa Bradley'); + + const rejectBtn = screen.getAllByTestId('rejectBtn'); + expect(rejectBtn).toHaveLength(2); + userEvent.click(rejectBtn[0]); + await waitFor(() => { + expect(toast.success).toHaveBeenCalledWith(t.requestRejected); + }); + }); + + it('GroupModal -> Click Requests -> Click Details', async () => { + renderGroupModal(link1, itemProps[0]); + expect(screen.getByText(t.manageGroup)).toBeInTheDocument(); + + const requestsBtn = screen.getByText(t.requests); + expect(requestsBtn).toBeInTheDocument(); + userEvent.click(requestsBtn); + + const detailsBtn = await screen.findByText(t.details); + expect(detailsBtn).toBeInTheDocument(); + userEvent.click(detailsBtn); + }); + + it('GroupModal -> Details -> Update', async () => { + renderGroupModal(link1, itemProps[0]); + expect(screen.getByText(t.manageGroup)).toBeInTheDocument(); + + const nameInput = screen.getByLabelText(`${t.name} *`); + expect(nameInput).toBeInTheDocument(); + fireEvent.change(nameInput, { target: { value: 'Group 2' } }); + expect(nameInput).toHaveValue('Group 2'); + + const descInput = screen.getByLabelText(t.description); + expect(descInput).toBeInTheDocument(); + fireEvent.change(descInput, { target: { value: 'desc new' } }); + expect(descInput).toHaveValue('desc new'); + + const vrInput = screen.getByLabelText(t.volunteersRequired); + expect(vrInput).toBeInTheDocument(); + fireEvent.change(vrInput, { target: { value: '10' } }); + expect(vrInput).toHaveValue('10'); + + const submitBtn = screen.getByTestId('submitBtn'); + expect(submitBtn).toBeInTheDocument(); + userEvent.click(submitBtn); + + await waitFor(() => { + expect(toast.success).toHaveBeenCalledWith(t.volunteerGroupUpdated); + expect(itemProps[0].refetchGroups).toHaveBeenCalled(); + expect(itemProps[0].hide).toHaveBeenCalled(); + }); + }); + + it('GroupModal -> Details -> Update -> Error', async () => { + renderGroupModal(link2, itemProps[0]); + expect(screen.getByText(t.manageGroup)).toBeInTheDocument(); + + const nameInput = screen.getByLabelText(`${t.name} *`); + expect(nameInput).toBeInTheDocument(); + fireEvent.change(nameInput, { target: { value: 'Group 2' } }); + expect(nameInput).toHaveValue('Group 2'); + + const descInput = screen.getByLabelText(t.description); + expect(descInput).toBeInTheDocument(); + fireEvent.change(descInput, { target: { value: 'desc new' } }); + expect(descInput).toHaveValue('desc new'); + + const vrInput = screen.getByLabelText(t.volunteersRequired); + expect(vrInput).toBeInTheDocument(); + fireEvent.change(vrInput, { target: { value: '10' } }); + expect(vrInput).toHaveValue('10'); + + const submitBtn = screen.getByTestId('submitBtn'); + expect(submitBtn).toBeInTheDocument(); + userEvent.click(submitBtn); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalled(); + }); + }); + + it('GroupModal -> Requests -> Accept -> Error', async () => { + renderGroupModal(link2, itemProps[0]); + expect(screen.getByText(t.manageGroup)).toBeInTheDocument(); + + const requestsBtn = screen.getByText(t.requests); + expect(requestsBtn).toBeInTheDocument(); + userEvent.click(requestsBtn); + + const userName = await screen.findAllByTestId('userName'); + expect(userName).toHaveLength(2); + expect(userName[0]).toHaveTextContent('John Doe'); + expect(userName[1]).toHaveTextContent('Teresa Bradley'); + + const acceptBtn = screen.getAllByTestId('acceptBtn'); + expect(acceptBtn).toHaveLength(2); + userEvent.click(acceptBtn[0]); + await waitFor(() => { + expect(toast.error).toHaveBeenCalled(); + }); + }); + + it('Try adding different values for volunteersRequired', async () => { + renderGroupModal(link1, itemProps[1]); + expect(screen.getByText(t.manageGroup)).toBeInTheDocument(); + + const vrInput = screen.getByLabelText(t.volunteersRequired); + expect(vrInput).toBeInTheDocument(); + fireEvent.change(vrInput, { target: { value: '-1' } }); + + await waitFor(() => { + expect(vrInput).toHaveValue(''); + }); + + userEvent.clear(vrInput); + userEvent.type(vrInput, '1{backspace}'); + + await waitFor(() => { + expect(vrInput).toHaveValue(''); + }); + + fireEvent.change(vrInput, { target: { value: '0' } }); + await waitFor(() => { + expect(vrInput).toHaveValue(''); + }); + + fireEvent.change(vrInput, { target: { value: '19' } }); + await waitFor(() => { + expect(vrInput).toHaveValue('19'); + }); + }); + + it('GroupModal -> Details -> No values updated', async () => { + renderGroupModal(link1, itemProps[0]); + expect(screen.getByText(t.manageGroup)).toBeInTheDocument(); + + const submitBtn = screen.getByTestId('submitBtn'); + expect(submitBtn).toBeInTheDocument(); + userEvent.click(submitBtn); + + await waitFor(() => { + expect(toast.success).toHaveBeenCalled(); + }); + }); +}); diff --git a/src/screens/UserPortal/Volunteer/Groups/GroupModal.tsx b/src/screens/UserPortal/Volunteer/Groups/GroupModal.tsx new file mode 100644 index 0000000000..27f461b462 --- /dev/null +++ b/src/screens/UserPortal/Volunteer/Groups/GroupModal.tsx @@ -0,0 +1,415 @@ +import type { ChangeEvent } from 'react'; +import { Button, Form, Modal } from 'react-bootstrap'; +import type { + InterfaceCreateVolunteerGroup, + InterfaceVolunteerGroupInfo, + InterfaceVolunteerMembership, +} from 'utils/interfaces'; +import styles from 'style/app.module.css'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { useMutation, useQuery } from '@apollo/client'; +import { toast } from 'react-toastify'; +import { + FormControl, + Paper, + Stack, + Table, + TableBody, + TableCell, + TableContainer, + TableHead, + TableRow, + TextField, +} from '@mui/material'; +import { + UPDATE_VOLUNTEER_GROUP, + UPDATE_VOLUNTEER_MEMBERSHIP, +} from 'GraphQl/Mutations/EventVolunteerMutation'; +import { PiUserListBold } from 'react-icons/pi'; +import { TbListDetails } from 'react-icons/tb'; +import { USER_VOLUNTEER_MEMBERSHIP } from 'GraphQl/Queries/EventVolunteerQueries'; +import Avatar from 'components/Avatar/Avatar'; +import { FaXmark } from 'react-icons/fa6'; + +export interface InterfaceGroupModal { + isOpen: boolean; + hide: () => void; + eventId: string; + group: InterfaceVolunteerGroupInfo; + refetchGroups: () => void; +} + +/** + * A modal dialog for creating or editing a volunteer group. + * + * @param isOpen - Indicates whether the modal is open. + * @param hide - Function to close the modal. + * @param eventId - The ID of the event associated with volunteer group. + * @param orgId - The ID of the organization associated with volunteer group. + * @param group - The volunteer group object to be edited. + * @param refetchGroups - Function to refetch the volunteer groups after creation or update. + * @returns The rendered modal component. + * + * The `VolunteerGroupModal` component displays a form within a modal dialog for creating or editing a Volunteer Group. + * It includes fields for entering the group name, description, volunteersRequired, and selecting volunteers/leaders. + * + * The modal includes: + * - A header with a title indicating the current mode (create or edit) and a close button. + * - A form with: + * - An input field for entering the group name. + * - A textarea for entering the group description. + * - An input field for entering the number of volunteers required. + * - A submit button to create or update the pledge. + * + * On form submission, the component either: + * - Calls `updateVoluneerGroup` mutation to update an existing group, or + * + * Success or error messages are displayed using toast notifications based on the result of the mutation. + */ + +const GroupModal: React.FC = ({ + isOpen, + hide, + eventId, + group, + refetchGroups, +}) => { + const { t } = useTranslation('translation', { + keyPrefix: 'eventVolunteers', + }); + const { t: tCommon } = useTranslation('common'); + + const [modalType, setModalType] = useState<'details' | 'requests'>('details'); + const [formState, setFormState] = useState({ + name: group.name, + description: group.description ?? '', + leader: group.leader, + volunteerUsers: group.volunteers.map((volunteer) => volunteer.user), + volunteersRequired: group.volunteersRequired ?? null, + }); + + const [updateVolunteerGroup] = useMutation(UPDATE_VOLUNTEER_GROUP); + const [updateMembership] = useMutation(UPDATE_VOLUNTEER_MEMBERSHIP); + + const updateMembershipStatus = async ( + id: string, + status: 'accepted' | 'rejected', + ): Promise => { + try { + await updateMembership({ + variables: { + id: id, + status: status, + }, + }); + toast.success( + t( + status === 'accepted' ? 'requestAccepted' : 'requestRejected', + ) as string, + ); + refetchRequests(); + } catch (error: unknown) { + toast.error((error as Error).message); + } + }; + + /** + * Query to fetch volunteer Membership requests for the event. + */ + const { + data: requestsData, + refetch: refetchRequests, + }: { + data?: { + getVolunteerMembership: InterfaceVolunteerMembership[]; + }; + refetch: () => void; + } = useQuery(USER_VOLUNTEER_MEMBERSHIP, { + variables: { + where: { + eventId, + groupId: group._id, + status: 'requested', + }, + }, + }); + + const requests = useMemo(() => { + if (!requestsData) return []; + return requestsData.getVolunteerMembership; + }, [requestsData]); + + useEffect(() => { + setFormState({ + name: group.name, + description: group.description ?? '', + leader: group.leader, + volunteerUsers: group.volunteers.map((volunteer) => volunteer.user), + volunteersRequired: group.volunteersRequired ?? null, + }); + }, [group]); + + const { name, description, volunteersRequired } = formState; + + const updateGroupHandler = useCallback( + async (e: ChangeEvent): Promise => { + e.preventDefault(); + + const updatedFields: { + [key: string]: number | string | undefined | null; + } = {}; + + if (name !== group?.name) { + updatedFields.name = name; + } + if (description !== group?.description) { + updatedFields.description = description; + } + if (volunteersRequired !== group?.volunteersRequired) { + updatedFields.volunteersRequired = volunteersRequired; + } + try { + await updateVolunteerGroup({ + variables: { + id: group?._id, + data: { ...updatedFields, eventId }, + }, + }); + toast.success(t('volunteerGroupUpdated')); + refetchGroups(); + hide(); + } catch (error: unknown) { + console.log(error); + toast.error((error as Error).message); + } + }, + [formState, group], + ); + + return ( + + +

{t('manageGroup')}

+ +
+ +
+ setModalType('details')} + /> + + + setModalType('requests')} + checked={modalType === 'requests'} + /> + +
+ + {modalType === 'details' ? ( +
+ {/* Input field to enter the group name */} + + + + setFormState({ ...formState, name: e.target.value }) + } + /> + + + {/* Input field to enter the group description */} + + + + setFormState({ ...formState, description: e.target.value }) + } + /> + + + + + + { + if (parseInt(e.target.value) > 0) { + setFormState({ + ...formState, + volunteersRequired: parseInt(e.target.value), + }); + } else if (e.target.value === '') { + setFormState({ + ...formState, + volunteersRequired: null, + }); + } + }} + /> + + + + {/* Button to submit the pledge form */} + +
+ ) : ( +
+ {requests.length === 0 ? ( + + {t('noRequests')} + + ) : ( + + + + + Name + Actions + + + + {requests.map((request, index) => { + const { _id, firstName, lastName, image } = + request.volunteer.user; + return ( + + + {image ? ( + volunteer + ) : ( +
+ +
+ )} + {firstName + ' ' + lastName} +
+ +
+ + +
+
+
+ ); + })} +
+
+
+ )} +
+ )} +
+
+ ); +}; +export default GroupModal; diff --git a/src/screens/UserPortal/Volunteer/Groups/Groups.mocks.ts b/src/screens/UserPortal/Volunteer/Groups/Groups.mocks.ts new file mode 100644 index 0000000000..204326ee8d --- /dev/null +++ b/src/screens/UserPortal/Volunteer/Groups/Groups.mocks.ts @@ -0,0 +1,468 @@ +import { + UPDATE_VOLUNTEER_GROUP, + UPDATE_VOLUNTEER_MEMBERSHIP, +} from 'GraphQl/Mutations/EventVolunteerMutation'; +import { + EVENT_VOLUNTEER_GROUP_LIST, + USER_VOLUNTEER_MEMBERSHIP, +} from 'GraphQl/Queries/EventVolunteerQueries'; + +const group1 = { + _id: 'groupId1', + name: 'Group 1', + description: 'desc', + volunteersRequired: null, + createdAt: '2024-10-25T16:16:32.978Z', + creator: { + _id: 'creatorId1', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + }, + leader: { + _id: 'userId', + firstName: 'Teresa', + lastName: 'Bradley', + image: 'img-url', + }, + volunteers: [ + { + _id: 'volunteerId1', + user: { + _id: 'userId', + firstName: 'Teresa', + lastName: 'Bradley', + image: null, + }, + }, + ], + assignments: [], + event: { + _id: 'eventId1', + }, +}; + +const group2 = { + _id: 'groupId2', + name: 'Group 2', + description: 'desc', + volunteersRequired: null, + createdAt: '2024-10-27T15:25:13.044Z', + creator: { + _id: 'creatorId2', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + }, + leader: { + _id: 'userId', + firstName: 'Teresa', + lastName: 'Bradley', + image: null, + }, + volunteers: [ + { + _id: 'volunteerId2', + user: { + _id: 'userId', + firstName: 'Teresa', + lastName: 'Bradley', + image: null, + }, + }, + ], + assignments: [], + event: { + _id: 'eventId2', + }, +}; + +const group3 = { + _id: 'groupId3', + name: 'Group 3', + description: 'desc', + volunteersRequired: null, + createdAt: '2024-10-27T15:34:15.889Z', + creator: { + _id: 'creatorId3', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + }, + leader: { + _id: 'userId1', + firstName: 'Bruce', + lastName: 'Garza', + image: null, + }, + volunteers: [ + { + _id: 'volunteerId3', + user: { + _id: 'userId', + firstName: 'Teresa', + lastName: 'Bradley', + image: null, + }, + }, + ], + assignments: [], + event: { + _id: 'eventId3', + }, +}; + +const membership1 = { + _id: 'membershipId1', + status: 'requested', + createdAt: '2024-10-29T10:18:05.851Z', + event: { + _id: 'eventId', + title: 'Event 1', + startDate: '2044-10-31', + }, + volunteer: { + _id: 'volunteerId1', + user: { + _id: 'userId1', + firstName: 'John', + lastName: 'Doe', + image: 'img-url', + }, + }, + group: { + _id: 'groupId', + name: 'Group 1', + }, +}; + +const membership2 = { + _id: 'membershipId2', + status: 'requested', + createdAt: '2024-10-29T10:18:05.851Z', + event: { + _id: 'eventId', + title: 'Event 1', + startDate: '2044-10-31', + }, + volunteer: { + _id: 'volunteerId2', + user: { + _id: 'userId2', + firstName: 'Teresa', + lastName: 'Bradley', + image: null, + }, + }, + group: { + _id: 'groupId', + name: 'Group 2', + }, +}; + +export const MOCKS = [ + { + request: { + query: EVENT_VOLUNTEER_GROUP_LIST, + variables: { + where: { + userId: 'userId', + orgId: 'orgId', + leaderName: null, + name_contains: '', + }, + orderBy: null, + }, + }, + result: { + data: { + getEventVolunteerGroups: [group1, group2, group3], + }, + }, + }, + { + request: { + query: EVENT_VOLUNTEER_GROUP_LIST, + variables: { + where: { + userId: 'userId', + orgId: 'orgId', + leaderName: null, + name_contains: '', + }, + orderBy: 'volunteers_DESC', + }, + }, + result: { + data: { + getEventVolunteerGroups: [group1, group2], + }, + }, + }, + { + request: { + query: EVENT_VOLUNTEER_GROUP_LIST, + variables: { + where: { + userId: 'userId', + orgId: 'orgId', + leaderName: null, + name_contains: '', + }, + orderBy: 'volunteers_ASC', + }, + }, + result: { + data: { + getEventVolunteerGroups: [group2, group1], + }, + }, + }, + { + request: { + query: EVENT_VOLUNTEER_GROUP_LIST, + variables: { + where: { + userId: 'userId', + orgId: 'orgId', + leaderName: null, + name_contains: '1', + }, + orderBy: null, + }, + }, + result: { + data: { + getEventVolunteerGroups: [group1], + }, + }, + }, + { + request: { + query: EVENT_VOLUNTEER_GROUP_LIST, + variables: { + where: { + userId: 'userId', + orgId: 'orgId', + leaderName: '', + name_contains: null, + }, + orderBy: null, + }, + }, + result: { + data: { + getEventVolunteerGroups: [group1, group2, group3], + }, + }, + }, + { + request: { + query: EVENT_VOLUNTEER_GROUP_LIST, + variables: { + where: { + userId: 'userId', + orgId: 'orgId', + leaderName: 'Bruce', + name_contains: null, + }, + orderBy: null, + }, + }, + result: { + data: { + getEventVolunteerGroups: [group3], + }, + }, + }, + { + request: { + query: USER_VOLUNTEER_MEMBERSHIP, + variables: { + where: { + eventId: 'eventId', + groupId: 'groupId', + status: 'requested', + }, + }, + }, + result: { + data: { + getVolunteerMembership: [membership1, membership2], + }, + }, + }, + { + request: { + query: UPDATE_VOLUNTEER_MEMBERSHIP, + variables: { + id: 'membershipId1', + status: 'accepted', + }, + }, + result: { + data: { + updateVolunteerMembership: { + _id: 'membershipId1', + }, + }, + }, + }, + { + request: { + query: UPDATE_VOLUNTEER_MEMBERSHIP, + variables: { + id: 'membershipId1', + status: 'rejected', + }, + }, + result: { + data: { + updateVolunteerMembership: { + _id: 'membershipId1', + }, + }, + }, + }, + { + request: { + query: UPDATE_VOLUNTEER_GROUP, + variables: { + id: 'groupId', + data: { + eventId: 'eventId', + name: 'Group 2', + description: 'desc new', + volunteersRequired: 10, + }, + }, + }, + result: { + data: { + updateEventVolunteerGroup: { + _id: 'groupId', + }, + }, + }, + }, + { + request: { + query: UPDATE_VOLUNTEER_GROUP, + variables: { + id: 'groupId', + data: { + eventId: 'eventId', + }, + }, + }, + result: { + data: { + updateEventVolunteerGroup: { + _id: 'groupId', + }, + }, + }, + }, +]; + +export const EMPTY_MOCKS = [ + { + request: { + query: EVENT_VOLUNTEER_GROUP_LIST, + variables: { + where: { + userId: 'userId', + orgId: 'orgId', + leaderName: null, + name_contains: '', + }, + orderBy: null, + }, + }, + result: { + data: { + getEventVolunteerGroups: [], + }, + }, + }, + { + request: { + query: USER_VOLUNTEER_MEMBERSHIP, + variables: { + where: { + eventId: 'eventId', + group: 'groupId', + status: 'requested', + }, + }, + }, + result: { + data: { + getVolunteerMembership: [], + }, + }, + }, +]; + +export const ERROR_MOCKS = [ + { + request: { + query: EVENT_VOLUNTEER_GROUP_LIST, + variables: { + where: { + userId: 'userId', + orgId: 'orgId', + leaderName: null, + name_contains: '', + }, + orderBy: null, + }, + }, + error: new Error('Mock Graphql EVENT_VOLUNTEER_GROUP_LIST Error'), + }, +]; + +export const UPDATE_ERROR_MOCKS = [ + { + request: { + query: USER_VOLUNTEER_MEMBERSHIP, + variables: { + where: { + eventId: 'eventId', + groupId: 'groupId', + status: 'requested', + }, + }, + }, + result: { + data: { + getVolunteerMembership: [membership1, membership2], + }, + }, + }, + { + request: { + query: UPDATE_VOLUNTEER_MEMBERSHIP, + variables: { + id: 'membershipId1', + status: 'accepted', + }, + }, + error: new Error('Mock Graphql UPDATE_VOLUNTEER_MEMBERSHIP Error'), + }, + { + request: { + query: UPDATE_VOLUNTEER_GROUP, + variables: { + id: 'groupId', + data: { + eventId: 'eventId', + name: 'Group 2', + description: 'desc new', + volunteersRequired: 10, + }, + }, + }, + error: new Error('Mock Graphql UPDATE_VOLUNTEER_GROUP Error'), + }, +]; diff --git a/src/screens/UserPortal/Volunteer/Groups/Groups.spec.tsx b/src/screens/UserPortal/Volunteer/Groups/Groups.spec.tsx new file mode 100644 index 0000000000..b9bf6c29c0 --- /dev/null +++ b/src/screens/UserPortal/Volunteer/Groups/Groups.spec.tsx @@ -0,0 +1,276 @@ +import React, { act } 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 i18n from 'utils/i18nForTest'; +import Groups from './Groups'; +import type { ApolloLink } from '@apollo/client'; +import { MOCKS, EMPTY_MOCKS, ERROR_MOCKS } from './Groups.mocks'; +import useLocalStorage from 'utils/useLocalstorage'; +import { vi } from 'vitest'; + +const { setItem } = useLocalStorage(); + +const link1 = new StaticMockLink(MOCKS); +const link2 = new StaticMockLink(ERROR_MOCKS); +const link3 = new StaticMockLink(EMPTY_MOCKS); +const t = { + ...JSON.parse( + JSON.stringify( + i18n.getDataByLanguage('en')?.translation.eventVolunteers ?? {}, + ), + ), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.common ?? {})), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.errors ?? {})), +}; + +/** + * Introduces a delay for the specified duration. + * This is primarily used to simulate debounce behavior in tests. + * @param ms - The duration to delay in milliseconds. Defaults to 300ms. + * @returns A Promise that resolves after the specified duration. + */ + +const debounceWait = async (ms = 300): Promise => { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +}; + +/** + * Renders the Groups component using a specific Apollo link. + * @param link - The ApolloLink instance to use for mocking GraphQL requests. + * @returns The rendered component wrapped in test utilities. + */ +const renderGroups = (link: ApolloLink): RenderResult => { + return render( + + + + + + + } /> +
} + /> + + + + + + , + ); +}; + +/** + * Describes the testing suite for the Groups screen. + */ +describe('Testing Groups Screen', () => { + beforeAll(() => { + vi.mock('react-router-dom', async () => { + const actual = await vi.importActual('react-router-dom'); + return { + ...actual, + useParams: () => ({ orgId: 'orgId' }), + }; + }); + }); + + beforeEach(() => { + setItem('userId', 'userId'); + }); + + afterEach(() => { + vi.resetAllMocks(); + cleanup(); // from @testing-library/react + }); + + /** + * Tests redirection to the fallback URL when required URL parameters are missing. + * Ensures the "paramsError" element is displayed. + */ + it('should redirect to fallback URL if URL params are undefined', async () => { + setItem('userId', null); + render( + + + + + + } /> +
} + /> + + + + + , + ); + + await waitFor(() => { + expect(screen.getByTestId('paramsError')).toBeInTheDocument(); + }); + }); + + /** + * Checks if the Groups screen renders correctly with the expected elements. + */ + it('should render Groups screen', async () => { + renderGroups(link1); + const searchInput = await screen.findByTestId('searchBy'); + expect(searchInput).toBeInTheDocument(); + // Verify other critical UI elements + expect(await screen.findByTestId('sort')).toBeInTheDocument(); + expect(await screen.findByTestId('searchByToggle')).toBeInTheDocument(); + const groupElements = await screen.findAllByTestId('groupName'); + expect(groupElements.length).toBeGreaterThan(0); + }); + + /** + * Verifies the sorting functionality of the Groups screen. + */ + it('Check Sorting Functionality', async () => { + renderGroups(link1); + const searchInput = await screen.findByTestId('searchBy'); + expect(searchInput).toBeInTheDocument(); + + let sortBtn = await screen.findByTestId('sort'); + expect(sortBtn).toBeInTheDocument(); + + // Sort by members_DESC + fireEvent.click(sortBtn); + const volunteersDESC = await screen.findByTestId('volunteers_DESC'); + expect(volunteersDESC).toBeInTheDocument(); + fireEvent.click(volunteersDESC); + + let groupName = await screen.findAllByTestId('groupName'); + expect(groupName[0]).toHaveTextContent('Group 1'); + + // Sort by members_ASC + sortBtn = await screen.findByTestId('sort'); + expect(sortBtn).toBeInTheDocument(); + fireEvent.click(sortBtn); + const volunteersASC = await screen.findByTestId('volunteers_ASC'); + expect(volunteersASC).toBeInTheDocument(); + fireEvent.click(volunteersASC); + + groupName = await screen.findAllByTestId('groupName'); + expect(groupName[0]).toHaveTextContent('Group 2'); + }); + + /** + * Verifies the search by group functionality of the Groups screen. + */ + it('Search by Groups', async () => { + renderGroups(link1); + const searchInput = await screen.findByTestId('searchBy'); + expect(searchInput).toBeInTheDocument(); + + const searchToggle = await screen.findByTestId('searchByToggle'); + expect(searchToggle).toBeInTheDocument(); + userEvent.click(searchToggle); + + const searchByGroup = await screen.findByTestId('group'); + expect(searchByGroup).toBeInTheDocument(); + userEvent.click(searchByGroup); + + userEvent.type(searchInput, '1'); + await debounceWait(); + + const groupName = await screen.findAllByTestId('groupName'); + expect(groupName[0]).toHaveTextContent('Group 1'); + }); + + /** + * Verifies the search by leader functionality of the Groups screen. + */ + it('Search by Leader', async () => { + renderGroups(link1); + const searchInput = await screen.findByTestId('searchBy'); + expect(searchInput).toBeInTheDocument(); + + const searchToggle = await screen.findByTestId('searchByToggle'); + expect(searchToggle).toBeInTheDocument(); + userEvent.click(searchToggle); + + const searchByLeader = await screen.findByTestId('leader'); + expect(searchByLeader).toBeInTheDocument(); + userEvent.click(searchByLeader); + + // Search by name on press of ENTER + userEvent.type(searchInput, 'Bruce'); + await debounceWait(); + + const groupName = await screen.findAllByTestId('groupName'); + expect(groupName[0]).toHaveTextContent('Group 1'); + }); + + /** + * Verifies the behavior when there are no groups to display. + */ + it('should render screen with No Groups', async () => { + renderGroups(link3); + + await waitFor(() => { + expect(screen.getByTestId('searchBy')).toBeInTheDocument(); + expect(screen.getByText(t.noVolunteerGroups)).toBeInTheDocument(); + }); + }); + + /** + * Verifies the error handling when there is an issue fetching groups data. + */ + it('Error while fetching groups data', async () => { + renderGroups(link2); + + await waitFor(() => { + expect(screen.getByTestId('errorMsg')).toBeInTheDocument(); + }); + }); + + /** + * Verifies the functionality of opening and closing the ViewModal. + */ + it('Open and close ViewModal', async () => { + renderGroups(link1); + + const viewGroupBtn = await screen.findAllByTestId('viewGroupBtn'); + userEvent.click(viewGroupBtn[0]); + + expect(await screen.findByText(t.groupDetails)).toBeInTheDocument(); + userEvent.click(await screen.findByTestId('volunteerViewModalCloseBtn')); + }); + + /** + * Verifies the functionality of opening and closing the GroupModal. + */ + it('Open and close GroupModal', async () => { + renderGroups(link1); + + const editGroupBtn = await screen.findAllByTestId('editGroupBtn'); + userEvent.click(editGroupBtn[0]); + + expect(await screen.findByText(t.manageGroup)).toBeInTheDocument(); + userEvent.click(await screen.findByTestId('modalCloseBtn')); + }); +}); diff --git a/src/screens/UserPortal/Volunteer/Groups/Groups.tsx b/src/screens/UserPortal/Volunteer/Groups/Groups.tsx new file mode 100644 index 0000000000..160dc0b23a --- /dev/null +++ b/src/screens/UserPortal/Volunteer/Groups/Groups.tsx @@ -0,0 +1,415 @@ +import React, { useCallback, useMemo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Button, Dropdown, Form } from 'react-bootstrap'; +import { Navigate, useParams } from 'react-router-dom'; + +import { Search, Sort, WarningAmberRounded } from '@mui/icons-material'; + +import { useQuery } from '@apollo/client'; + +import type { InterfaceVolunteerGroupInfo } from 'utils/interfaces'; +import Loader from 'components/Loader/Loader'; +import { + DataGrid, + type GridCellParams, + type GridColDef, +} from '@mui/x-data-grid'; +import { debounce, Stack } from '@mui/material'; +import Avatar from 'components/Avatar/Avatar'; +import styles from '../../../../style/app.module.css'; +import { EVENT_VOLUNTEER_GROUP_LIST } from 'GraphQl/Queries/EventVolunteerQueries'; +import VolunteerGroupViewModal from 'screens/EventVolunteers/VolunteerGroups/VolunteerGroupViewModal'; +import useLocalStorage from 'utils/useLocalstorage'; +import GroupModal from './GroupModal'; + +enum ModalState { + EDIT = 'edit', + VIEW = 'view', +} + +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', + }, +}; + +/** + * Component for managing volunteer groups for an event. + * This component allows users to view, filter, sort, and create action items. It also provides a modal for creating and editing action items. + * @returns The rendered component. + */ +function groups(): JSX.Element { + const { t } = useTranslation('translation', { + keyPrefix: 'eventVolunteers', + }); + const { t: tCommon } = useTranslation('common'); + const { t: tErrors } = useTranslation('errors'); + + const { getItem } = useLocalStorage(); + const userId = getItem('userId'); + + // Get the organization ID from URL parameters + const { orgId } = useParams(); + + if (!orgId || !userId) { + return ; + } + + const [group, setGroup] = useState(null); + const [searchValue, setSearchValue] = useState(''); + const [searchTerm, setSearchTerm] = useState(''); + const [sortBy, setSortBy] = useState< + 'volunteers_ASC' | 'volunteers_DESC' | null + >(null); + const [searchBy, setSearchBy] = useState<'leader' | 'group'>('group'); + const [modalState, setModalState] = useState<{ + [key in ModalState]: boolean; + }>({ + [ModalState.EDIT]: false, + [ModalState.VIEW]: false, + }); + + const debouncedSearch = useMemo( + () => debounce((value: string) => setSearchTerm(value), 300), + [], + ); + + /** + * Query to fetch the list of volunteer groups for the event. + */ + const { + data: groupsData, + loading: groupsLoading, + error: groupsError, + refetch: refetchGroups, + }: { + data?: { + getEventVolunteerGroups: InterfaceVolunteerGroupInfo[]; + }; + loading: boolean; + error?: Error | undefined; + refetch: () => void; + } = useQuery(EVENT_VOLUNTEER_GROUP_LIST, { + variables: { + where: { + eventId: undefined, + userId, + orgId, + leaderName: searchBy === 'leader' ? searchTerm : null, + name_contains: searchBy === 'group' ? searchTerm : null, + }, + orderBy: sortBy, + }, + }); + + const openModal = (modal: ModalState): void => + setModalState((prevState) => ({ ...prevState, [modal]: true })); + + const closeModal = (modal: ModalState): void => + setModalState((prevState) => ({ ...prevState, [modal]: false })); + + const handleModalClick = useCallback( + (group: InterfaceVolunteerGroupInfo | null, modal: ModalState): void => { + setGroup(group); + openModal(modal); + }, + [openModal], + ); + + const groups = useMemo( + () => groupsData?.getEventVolunteerGroups || [], + [groupsData], + ); + + if (groupsLoading) { + return ; + } + + if (groupsError) { + return ( +
+ +
+ {tErrors('errorLoading', { entity: 'Volunteer Groups' })} +
+
+ ); + } + + const columns: GridColDef[] = [ + { + field: 'group', + headerName: 'Group', + flex: 1, + align: 'left', + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + return ( +
+ {params.row.name} +
+ ); + }, + }, + { + field: 'leader', + headerName: 'Leader', + flex: 1, + align: 'center', + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + const { _id, firstName, lastName, image } = params.row.leader; + return ( +
+ {image ? ( + Assignee + ) : ( +
+ +
+ )} + {firstName + ' ' + lastName} +
+ ); + }, + }, + { + field: 'actions', + headerName: 'Actions Completed', + flex: 1, + align: 'center', + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + return ( +
+ {params.row.assignments.length} +
+ ); + }, + }, + { + field: 'volunteers', + headerName: 'No. of Volunteers', + flex: 1, + align: 'center', + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + return ( +
+ {params.row.volunteers.length} +
+ ); + }, + }, + { + field: 'options', + headerName: 'Options', + align: 'center', + flex: 1, + minWidth: 100, + headerAlign: 'center', + sortable: false, + headerClassName: `${styles.tableHeader}`, + renderCell: (params: GridCellParams) => { + return ( + <> + + {params.row.leader._id === userId && ( + + )} + + ); + }, + }, + ]; + + return ( +
+ {/* Header with search, filter and Create Button */} +
+
+ { + setSearchValue(e.target.value); + debouncedSearch(e.target.value); + }} + data-testid="searchBy" + /> + +
+
+
+ + + + {tCommon('searchBy', { item: '' })} + + + setSearchBy('leader')} + data-testid="leader" + > + {t('leader')} + + setSearchBy('group')} + data-testid="group" + > + {t('group')} + + + + + + + {tCommon('sort')} + + + setSortBy('volunteers_DESC')} + data-testid="volunteers_DESC" + > + {t('mostVolunteers')} + + setSortBy('volunteers_ASC')} + data-testid="volunteers_ASC" + > + {t('leastVolunteers')} + + + +
+
+
+ + {/* Table with Volunteer Groups */} + row._id} + slots={{ + noRowsOverlay: () => ( + + {t('noVolunteerGroups')} + + ), + }} + sx={dataGridStyle} + getRowClassName={() => `${styles.rowBackground}`} + autoHeight + rowHeight={65} + rows={groups.map((group, index) => ({ + id: index + 1, + ...group, + }))} + columns={columns} + isRowSelectable={() => false} + /> + + {group && ( + <> + closeModal(ModalState.EDIT)} + refetchGroups={refetchGroups} + group={group} + eventId={group.event._id} + /> + closeModal(ModalState.VIEW)} + group={group} + /> + + )} +
+ ); +} + +export default groups; diff --git a/src/screens/UserPortal/Volunteer/Invitations/Invitations.mocks.ts b/src/screens/UserPortal/Volunteer/Invitations/Invitations.mocks.ts new file mode 100644 index 0000000000..c400d96939 --- /dev/null +++ b/src/screens/UserPortal/Volunteer/Invitations/Invitations.mocks.ts @@ -0,0 +1,263 @@ +import { UPDATE_VOLUNTEER_MEMBERSHIP } from 'GraphQl/Mutations/EventVolunteerMutation'; +import { USER_VOLUNTEER_MEMBERSHIP } from 'GraphQl/Queries/EventVolunteerQueries'; + +const membership1 = { + _id: 'membershipId1', + status: 'invited', + createdAt: '2024-10-29T10:18:05.851Z', + event: { + _id: 'eventId', + title: 'Event 1', + startDate: '2044-10-31', + }, + volunteer: { + _id: 'volunteerId1', + user: { + _id: 'userId', + firstName: 'John', + lastName: 'Doe', + image: 'img-url', + }, + }, + group: null, +}; + +const membership2 = { + _id: 'membershipId2', + status: 'invited', + createdAt: '2024-10-30T10:18:05.851Z', + event: { + _id: 'eventId', + title: 'Event 2', + startDate: '2044-11-31', + }, + volunteer: { + _id: 'volunteerId1', + user: { + _id: 'userId', + firstName: 'John', + lastName: 'Doe', + image: null, + }, + }, + group: { + _id: 'groupId1', + name: 'Group 1', + }, +}; + +export const MOCKS = [ + { + request: { + query: USER_VOLUNTEER_MEMBERSHIP, + variables: { + where: { + userId: 'userId', + status: 'invited', + filter: null, + }, + }, + }, + result: { + data: { + getVolunteerMembership: [membership1, membership2], + }, + }, + }, + { + request: { + query: USER_VOLUNTEER_MEMBERSHIP, + variables: { + where: { + userId: 'userId', + status: 'invited', + filter: null, + }, + orderBy: 'createdAt_DESC', + }, + }, + result: { + data: { + getVolunteerMembership: [membership2, membership1], + }, + }, + }, + { + request: { + query: USER_VOLUNTEER_MEMBERSHIP, + variables: { + where: { + userId: 'userId', + status: 'invited', + filter: null, + }, + orderBy: 'createdAt_ASC', + }, + }, + result: { + data: { + getVolunteerMembership: [membership1, membership2], + }, + }, + }, + { + request: { + query: USER_VOLUNTEER_MEMBERSHIP, + variables: { + where: { + userId: 'userId', + status: 'invited', + filter: 'group', + }, + }, + }, + result: { + data: { + getVolunteerMembership: [membership2], + }, + }, + }, + { + request: { + query: USER_VOLUNTEER_MEMBERSHIP, + variables: { + where: { + userId: 'userId', + status: 'invited', + filter: 'individual', + }, + }, + }, + result: { + data: { + getVolunteerMembership: [membership1], + }, + }, + }, + { + request: { + query: USER_VOLUNTEER_MEMBERSHIP, + variables: { + where: { + userId: 'userId', + status: 'invited', + filter: null, + eventTitle: '1', + }, + }, + }, + result: { + data: { + getVolunteerMembership: [membership1], + }, + }, + }, + { + request: { + query: UPDATE_VOLUNTEER_MEMBERSHIP, + variables: { + id: 'membershipId1', + status: 'accepted', + }, + }, + result: { + data: { + updateVolunteerMembership: { + _id: 'membershipId1', + }, + }, + }, + }, + { + request: { + query: UPDATE_VOLUNTEER_MEMBERSHIP, + variables: { + id: 'membershipId1', + status: 'rejected', + }, + }, + result: { + data: { + updateVolunteerMembership: { + _id: 'membershipId1', + }, + }, + }, + }, +]; + +export const EMPTY_MOCKS = [ + { + request: { + query: USER_VOLUNTEER_MEMBERSHIP, + variables: { + where: { + userId: 'userId', + status: 'invited', + filter: null, + }, + }, + }, + result: { + data: { + getVolunteerMembership: [], + }, + }, + }, +]; + +export const ERROR_MOCKS = [ + { + request: { + query: USER_VOLUNTEER_MEMBERSHIP, + variables: { + where: { + userId: 'userId', + status: 'invited', + filter: null, + }, + }, + }, + error: new Error('Mock Graphql USER_VOLUNTEER_MEMBERSHIP Error'), + }, + { + request: { + query: UPDATE_VOLUNTEER_MEMBERSHIP, + variables: { + id: 'membershipId1', + status: 'accepted', + }, + }, + error: new Error('Mock Graphql UPDATE_VOLUNTEER_MEMBERSHIP Error'), + }, +]; + +export const UPDATE_ERROR_MOCKS = [ + { + request: { + query: USER_VOLUNTEER_MEMBERSHIP, + variables: { + where: { + userId: 'userId', + status: 'invited', + filter: null, + }, + }, + }, + result: { + data: { + getVolunteerMembership: [membership1, membership2], + }, + }, + }, + { + request: { + query: UPDATE_VOLUNTEER_MEMBERSHIP, + variables: { + id: 'membershipId1', + status: 'accepted', + }, + }, + error: new Error('Mock Graphql UPDATE_VOLUNTEER_MEMBERSHIP Error'), + }, +]; diff --git a/src/screens/UserPortal/Volunteer/Invitations/Invitations.spec.tsx b/src/screens/UserPortal/Volunteer/Invitations/Invitations.spec.tsx new file mode 100644 index 0000000000..867f95c1aa --- /dev/null +++ b/src/screens/UserPortal/Volunteer/Invitations/Invitations.spec.tsx @@ -0,0 +1,306 @@ +import React, { act } 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 { 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 i18n from 'utils/i18nForTest'; +import Invitations from './Invitations'; +import type { ApolloLink } from '@apollo/client'; +import { + MOCKS, + EMPTY_MOCKS, + ERROR_MOCKS, + UPDATE_ERROR_MOCKS, +} from './Invitations.mocks'; +import { toast } from 'react-toastify'; +import useLocalStorage from 'utils/useLocalstorage'; +import { vi, expect } from 'vitest'; + +vi.mock('react-toastify', () => ({ + toast: { + success: vi.fn(), + error: vi.fn(), + }, +})); + +vi.mock('react-router-dom', async () => { + const actual = await vi.importActual('react-router-dom'); + return { + ...actual, + useParams: () => ({ orgId: 'orgId' }), + useNavigate: vi.fn(), + }; +}); + +const { setItem } = useLocalStorage(); + +const link1 = new StaticMockLink(MOCKS); +const link2 = new StaticMockLink(ERROR_MOCKS); +const link3 = new StaticMockLink(EMPTY_MOCKS); +const link4 = new StaticMockLink(UPDATE_ERROR_MOCKS); +const t = { + ...JSON.parse( + JSON.stringify( + i18n.getDataByLanguage('en')?.translation.userVolunteer ?? {}, + ), + ), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.common ?? {})), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.errors ?? {})), +}; + +const debounceWait = async (ms = 300): Promise => { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +}; + +const renderInvitations = (link: ApolloLink): RenderResult => { + return render( + + + + + + + } + /> +
} + /> + + + + + + , + ); +}; + +describe('Testing Invvitations Screen', () => { + beforeEach(() => { + setItem('userId', 'userId'); + }); + + afterAll(() => { + vi.clearAllMocks(); + }); + + it('should redirect to fallback URL if URL params are undefined', async () => { + setItem('userId', null); + render( + + + + + + } /> +
} + /> + + + + + , + ); + + await waitFor(() => { + expect(screen.getByTestId('paramsError')).toBeInTheDocument(); + }); + }); + + it('should render Invitations screen', async () => { + renderInvitations(link1); + const searchInput = await screen.findByTestId('searchBy'); + expect(searchInput).toBeInTheDocument(); + }); + + it('Check Sorting Functionality', async () => { + renderInvitations(link1); + const searchInput = await screen.findByTestId('searchBy'); + expect(searchInput).toBeInTheDocument(); + + let sortBtn = await screen.findByTestId('sort'); + expect(sortBtn).toBeInTheDocument(); + + // Sort by createdAt_DESC + fireEvent.click(sortBtn); + const createdAtDESC = await screen.findByTestId('createdAt_DESC'); + expect(createdAtDESC).toBeInTheDocument(); + fireEvent.click(createdAtDESC); + + let inviteSubject = await screen.findAllByTestId('inviteSubject'); + expect(inviteSubject[0]).toHaveTextContent( + 'Invitation to join volunteer group', + ); + + // Sort by createdAt_ASC + sortBtn = await screen.findByTestId('sort'); + expect(sortBtn).toBeInTheDocument(); + fireEvent.click(sortBtn); + const createdAtASC = await screen.findByTestId('createdAt_ASC'); + expect(createdAtASC).toBeInTheDocument(); + fireEvent.click(createdAtASC); + + inviteSubject = await screen.findAllByTestId('inviteSubject'); + expect(inviteSubject[0]).toHaveTextContent( + 'Invitation to volunteer for event', + ); + }); + + it('Filter Invitations (all)', async () => { + renderInvitations(link1); + const searchInput = await screen.findByTestId('searchBy'); + expect(searchInput).toBeInTheDocument(); + + // Filter by All + const filter = await screen.findByTestId('filter'); + expect(filter).toBeInTheDocument(); + + fireEvent.click(filter); + const filterAll = await screen.findByTestId('filterAll'); + expect(filterAll).toBeInTheDocument(); + + fireEvent.click(filterAll); + const inviteSubject = await screen.findAllByTestId('inviteSubject'); + expect(inviteSubject).toHaveLength(2); + }); + + it('Filter Invitations (group)', async () => { + renderInvitations(link1); + const searchInput = await screen.findByTestId('searchBy'); + expect(searchInput).toBeInTheDocument(); + + // Filter by All + const filter = await screen.findByTestId('filter'); + expect(filter).toBeInTheDocument(); + + fireEvent.click(filter); + const filterGroup = await screen.findByTestId('filterGroup'); + expect(filterGroup).toBeInTheDocument(); + + fireEvent.click(filterGroup); + const inviteSubject = await screen.findAllByTestId('inviteSubject'); + expect(inviteSubject).toHaveLength(1); + expect(inviteSubject[0]).toHaveTextContent( + 'Invitation to join volunteer group', + ); + }); + + it('Filter Invitations (individual)', async () => { + renderInvitations(link1); + const searchInput = await screen.findByTestId('searchBy'); + expect(searchInput).toBeInTheDocument(); + + // Filter by All + const filter = await screen.findByTestId('filter'); + expect(filter).toBeInTheDocument(); + + fireEvent.click(filter); + const filterIndividual = await screen.findByTestId('filterIndividual'); + expect(filterIndividual).toBeInTheDocument(); + + fireEvent.click(filterIndividual); + const inviteSubject = await screen.findAllByTestId('inviteSubject'); + expect(inviteSubject).toHaveLength(1); + expect(inviteSubject[0]).toHaveTextContent( + 'Invitation to volunteer for event', + ); + }); + + it('Search Invitations', async () => { + renderInvitations(link1); + const searchInput = await screen.findByTestId('searchBy'); + expect(searchInput).toBeInTheDocument(); + + // Search by name on press of ENTER + userEvent.type(searchInput, '1'); + await debounceWait(); + + await waitFor(() => { + const inviteSubject = screen.getAllByTestId('inviteSubject'); + expect(inviteSubject).toHaveLength(1); + expect(inviteSubject[0]).toHaveTextContent( + 'Invitation to volunteer for event', + ); + }); + }); + + it('should render screen with No Invitations', async () => { + renderInvitations(link3); + + await waitFor(() => { + expect(screen.getByTestId('searchBy')).toBeInTheDocument(); + expect(screen.getByText(t.noInvitations)).toBeInTheDocument(); + }); + }); + + it('Error while fetching invitations data', async () => { + renderInvitations(link2); + + await waitFor(() => { + expect(screen.getByTestId('errorMsg')).toBeInTheDocument(); + }); + }); + + it('Accept Invite', async () => { + renderInvitations(link1); + const searchInput = await screen.findByTestId('searchBy'); + expect(searchInput).toBeInTheDocument(); + + const acceptBtn = await screen.findAllByTestId('acceptBtn'); + expect(acceptBtn).toHaveLength(2); + + // Accept Request + userEvent.click(acceptBtn[0]); + + await waitFor(() => { + expect(toast.success).toHaveBeenCalledWith(t.invitationAccepted); + }); + }); + + it('Reject Invite', async () => { + renderInvitations(link1); + const searchInput = await screen.findByTestId('searchBy'); + expect(searchInput).toBeInTheDocument(); + + const rejectBtn = await screen.findAllByTestId('rejectBtn'); + expect(rejectBtn).toHaveLength(2); + + // Reject Request + userEvent.click(rejectBtn[0]); + + await waitFor(() => { + expect(toast.success).toHaveBeenCalledWith(t.invitationRejected); + }); + }); + + it('Error in Update Invite Mutation', async () => { + renderInvitations(link4); + const searchInput = await screen.findByTestId('searchBy'); + expect(searchInput).toBeInTheDocument(); + + const acceptBtn = await screen.findAllByTestId('acceptBtn'); + expect(acceptBtn).toHaveLength(2); + + // Accept Request + userEvent.click(acceptBtn[0]); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalled(); + }); + }); +}); diff --git a/src/screens/UserPortal/Volunteer/Invitations/Invitations.tsx b/src/screens/UserPortal/Volunteer/Invitations/Invitations.tsx new file mode 100644 index 0000000000..a79b64251d --- /dev/null +++ b/src/screens/UserPortal/Volunteer/Invitations/Invitations.tsx @@ -0,0 +1,297 @@ +import React, { useMemo, useState } from 'react'; +import { Dropdown, Form, Button } from 'react-bootstrap'; +import styles from '../VolunteerManagement.module.css'; +import { useTranslation } from 'react-i18next'; +import { Navigate, useParams } from 'react-router-dom'; +import { + FilterAltOutlined, + Search, + Sort, + WarningAmberRounded, +} from '@mui/icons-material'; +import { TbCalendarEvent } from 'react-icons/tb'; +import { FaUserGroup } from 'react-icons/fa6'; +import { debounce, Stack } from '@mui/material'; + +import useLocalStorage from 'utils/useLocalstorage'; +import { useMutation, useQuery } from '@apollo/client'; +import type { InterfaceVolunteerMembership } from 'utils/interfaces'; +import { FaRegClock } from 'react-icons/fa'; +import Loader from 'components/Loader/Loader'; +import { USER_VOLUNTEER_MEMBERSHIP } from 'GraphQl/Queries/EventVolunteerQueries'; +import { UPDATE_VOLUNTEER_MEMBERSHIP } from 'GraphQl/Mutations/EventVolunteerMutation'; +import { toast } from 'react-toastify'; + +enum ItemFilter { + Group = 'group', + Individual = 'individual', +} + +/** + * The `Invitations` component displays list of invites for the user to volunteer. + * It allows the user to search, sort, and accept/reject invites. + * + * @returns The rendered component displaying the upcoming events. + */ +const Invitations = (): JSX.Element => { + // Retrieves translation functions for various namespaces + const { t } = useTranslation('translation', { + keyPrefix: 'userVolunteer', + }); + 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 ; + } + + const debouncedSearch = useMemo( + () => debounce((value: string) => setSearchTerm(value), 300), + [], + ); + + const [searchTerm, setSearchTerm] = useState(''); + const [searchValue, setSearchValue] = useState(''); + const [filter, setFilter] = useState(null); + const [sortBy, setSortBy] = useState< + 'createdAt_ASC' | 'createdAt_DESC' | null + >(null); + + const [updateMembership] = useMutation(UPDATE_VOLUNTEER_MEMBERSHIP); + + const updateMembershipStatus = async ( + id: string, + status: 'accepted' | 'rejected', + ): Promise => { + try { + await updateMembership({ + variables: { + id: id, + status: status, + }, + }); + toast.success( + t( + status === 'accepted' ? 'invitationAccepted' : 'invitationRejected', + ) as string, + ); + refetchInvitations(); + } catch (error: unknown) { + toast.error((error as Error).message); + } + }; + + const { + data: invitationData, + loading: invitationLoading, + error: invitationError, + refetch: refetchInvitations, + }: { + data?: { + getVolunteerMembership: InterfaceVolunteerMembership[]; + }; + loading: boolean; + error?: Error | undefined; + refetch: () => void; + } = useQuery(USER_VOLUNTEER_MEMBERSHIP, { + variables: { + where: { + userId: userId, + status: 'invited', + filter: filter, + eventTitle: searchTerm ? searchTerm : undefined, + }, + orderBy: sortBy ? sortBy : undefined, + }, + }); + + const invitations = useMemo(() => { + if (!invitationData) return []; + return invitationData.getVolunteerMembership; + }, [invitationData]); + + // loads the invitations when the component mounts + if (invitationLoading) return ; + if (invitationError) { + // Displays an error message if there is an issue loading the invvitations + return ( +
+
+ +
+ {tErrors('errorLoading', { entity: 'Volunteership Invitations' })} +
+
+
+ ); + } + + // Renders the invitations list and UI elements for searching, sorting, and accepting/rejecting invites + return ( + <> +
+ {/* Search input field and button */} +
+ { + setSearchValue(e.target.value); + debouncedSearch(e.target.value); + }} + data-testid="searchBy" + /> + +
+
+
+ {/* Dropdown menu for sorting invitations */} + + + + {tCommon('sort')} + + + setSortBy('createdAt_DESC')} + data-testid="createdAt_DESC" + > + {t('receivedLatest')} + + setSortBy('createdAt_ASC')} + data-testid="createdAt_ASC" + > + {t('receivedEarliest')} + + + + + + + + {t('filter')} + + + setFilter(null)} + data-testid="filterAll" + > + {tCommon('all')} + + setFilter(ItemFilter.Group)} + data-testid="filterGroup" + > + {t('groupInvite')} + + setFilter(ItemFilter.Individual)} + data-testid="filterIndividual" + > + {t('individualInvite')} + + + +
+
+
+ {invitations.length < 1 ? ( + + {/* Displayed if no invitations are found */} + {t('noInvitations')} + + ) : ( + invitations.map((invite: InterfaceVolunteerMembership) => ( +
+
+
+ {invite.group ? ( + <>{t('groupInvitationSubject')} + ) : ( + <>{t('eventInvitationSubject')} + )} +
+
+ {invite.group && ( + <> +
+ + Group:{' '} + {invite.group.name} +
+ | + + )} +
+ + Event:{' '} + {invite.event.title} +
+ | +
+ + Received:{' '} + {new Date(invite.createdAt).toLocaleString()} +
+
+
+
+ + +
+
+ )) + )} + + ); +}; + +export default Invitations; diff --git a/src/screens/UserPortal/Volunteer/UpcomingEvents/UpcomingEvents.mocks.ts b/src/screens/UserPortal/Volunteer/UpcomingEvents/UpcomingEvents.mocks.ts new file mode 100644 index 0000000000..ae00d52dbe --- /dev/null +++ b/src/screens/UserPortal/Volunteer/UpcomingEvents/UpcomingEvents.mocks.ts @@ -0,0 +1,281 @@ +import { CREATE_VOLUNTEER_MEMBERSHIP } from 'GraphQl/Mutations/EventVolunteerMutation'; +import { USER_EVENTS_VOLUNTEER } from 'GraphQl/Queries/PlugInQueries'; + +const event1 = { + _id: 'eventId1', + title: 'Event 1', + startDate: '2044-10-30', + endDate: '2044-10-30', + location: 'Mumbai', + startTime: null, + endTime: null, + allDay: true, + recurring: true, + volunteerGroups: [ + { + _id: 'groupId1', + name: 'Group 1', + volunteersRequired: null, + description: 'desc', + volunteers: [ + { + _id: 'volunteerId1', + }, + { + _id: 'volunteerId2', + }, + ], + }, + ], + volunteers: [ + { + _id: 'volunteerId1', + user: { + _id: 'userId1', + }, + }, + { + _id: 'volunteerId2', + user: { + _id: 'userId2', + }, + }, + ], +}; + +const event2 = { + _id: 'eventId2', + title: 'Event 2', + startDate: '2044-10-31', + endDate: '2044-10-31', + location: 'Pune', + startTime: null, + endTime: null, + allDay: true, + recurring: false, + volunteerGroups: [ + { + _id: 'groupId2', + name: 'Group 2', + volunteersRequired: null, + description: 'desc', + volunteers: [ + { + _id: 'volunteerId3', + }, + ], + }, + ], + volunteers: [ + { + _id: 'volunteerId3', + user: { + _id: 'userId3', + }, + }, + ], +}; + +const event3 = { + _id: 'eventId3', + title: 'Event 3', + startDate: '2044-10-31', + endDate: '2022-10-31', + location: 'Delhi', + startTime: null, + endTime: null, + description: 'desc', + allDay: true, + recurring: true, + volunteerGroups: [ + { + _id: 'groupId3', + name: 'Group 3', + volunteersRequired: null, + description: 'desc', + volunteers: [ + { + _id: 'userId', + }, + ], + }, + ], + volunteers: [ + { + _id: 'volunteerId', + user: { + _id: 'userId', + }, + }, + ], +}; + +export const MOCKS = [ + { + request: { + query: USER_EVENTS_VOLUNTEER, + variables: { + organization_id: 'orgId', + title_contains: '', + location_contains: '', + upcomingOnly: true, + first: null, + skip: null, + }, + }, + result: { + data: { + eventsByOrganizationConnection: [event1, event2, event3], + }, + }, + }, + { + request: { + query: USER_EVENTS_VOLUNTEER, + variables: { + organization_id: 'orgId', + title_contains: '1', + location_contains: '', + upcomingOnly: true, + first: null, + skip: null, + }, + }, + result: { + data: { + eventsByOrganizationConnection: [event1], + }, + }, + }, + { + request: { + query: USER_EVENTS_VOLUNTEER, + variables: { + organization_id: 'orgId', + title_contains: '', + location_contains: 'M', + upcomingOnly: true, + first: null, + skip: null, + }, + }, + result: { + data: { + eventsByOrganizationConnection: [event1], + }, + }, + }, + { + request: { + query: CREATE_VOLUNTEER_MEMBERSHIP, + variables: { + data: { + event: 'eventId1', + group: null, + status: 'requested', + userId: 'userId', + }, + }, + }, + result: { + data: { + createVolunteerMembership: { + _id: 'membershipId1', + }, + }, + }, + }, + { + request: { + query: CREATE_VOLUNTEER_MEMBERSHIP, + variables: { + data: { + event: 'eventId1', + group: 'groupId1', + status: 'requested', + userId: 'userId', + }, + }, + }, + result: { + data: { + createVolunteerMembership: { + _id: 'membershipId1', + }, + }, + }, + }, +]; + +export const EMPTY_MOCKS = [ + { + request: { + query: USER_EVENTS_VOLUNTEER, + variables: { + organization_id: 'orgId', + title_contains: '', + location_contains: '', + upcomingOnly: true, + first: null, + skip: null, + }, + }, + result: { + data: { + eventsByOrganizationConnection: [], + }, + }, + }, +]; + +export const ERROR_MOCKS = [ + { + request: { + query: USER_EVENTS_VOLUNTEER, + variables: { + organization_id: 'orgId', + title_contains: '', + location_contains: '', + upcomingOnly: true, + first: null, + skip: null, + }, + }, + error: new Error('Mock Graphql USER_EVENTS_VOLUNTEER Error'), + }, +]; + +export const CREATE_ERROR_MOCKS = [ + { + request: { + query: USER_EVENTS_VOLUNTEER, + variables: { + organization_id: 'orgId', + title_contains: '', + location_contains: '', + upcomingOnly: true, + first: null, + skip: null, + }, + }, + result: { + data: { + eventsByOrganizationConnection: [event1, event2], + }, + }, + }, + { + request: { + query: CREATE_VOLUNTEER_MEMBERSHIP, + variables: { + data: { + event: 'eventId1', + group: null, + status: 'requested', + userId: 'userId', + }, + }, + }, + error: new Error('Mock Graphql CREATE_VOLUNTEER_MEMBERSHIP Error'), + }, +]; diff --git a/src/screens/UserPortal/Volunteer/UpcomingEvents/UpcomingEvents.spec.tsx b/src/screens/UserPortal/Volunteer/UpcomingEvents/UpcomingEvents.spec.tsx new file mode 100644 index 0000000000..f636d8d8d4 --- /dev/null +++ b/src/screens/UserPortal/Volunteer/UpcomingEvents/UpcomingEvents.spec.tsx @@ -0,0 +1,236 @@ +import React, { act } 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 { 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 i18n from 'utils/i18nForTest'; +import UpcomingEvents from './UpcomingEvents'; +import type { ApolloLink } from '@apollo/client'; +import { + MOCKS, + EMPTY_MOCKS, + ERROR_MOCKS, + CREATE_ERROR_MOCKS, +} from './UpcomingEvents.mocks'; +import { toast } from 'react-toastify'; +import useLocalStorage from 'utils/useLocalstorage'; +import { vi } from 'vitest'; + +/** + * Unit tests for the UpcomingEvents component. + * + * This file contains tests to verify the functionality and behavior of the UpcomingEvents component + * under various scenarios, including successful data fetching, error handling, and user interactions. + * Mocked dependencies are used to ensure isolated testing of the component. + */ + +vi.mock('react-toastify', () => ({ + toast: { + success: vi.fn(), + error: vi.fn(), + }, +})); + +const { setItem } = useLocalStorage(); + +const link1 = new StaticMockLink(MOCKS); +const link2 = new StaticMockLink(ERROR_MOCKS); +const link3 = new StaticMockLink(EMPTY_MOCKS); +const link4 = new StaticMockLink(CREATE_ERROR_MOCKS); + +const t = { + ...JSON.parse( + JSON.stringify( + i18n.getDataByLanguage('en')?.translation.userVolunteer ?? {}, + ), + ), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.common ?? {})), + ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.errors ?? {})), +}; + +const debounceWait = async (ms = 300): Promise => { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +}; + +const renderUpcomingEvents = (link: ApolloLink): RenderResult => { + return render( + + + + + + + } + /> +
} + /> + + + + + + , + ); +}; + +describe('Testing Upcoming Events Screen', () => { + beforeAll(() => { + vi.mock('react-router-dom', async () => { + const actual = await vi.importActual('react-router-dom'); + return { + ...actual, + useParams: () => ({ orgId: 'orgId' }), + }; + }); + }); + + beforeEach(() => { + setItem('userId', 'userId'); + }); + + afterAll(() => { + vi.clearAllMocks(); + }); + + it('should redirect to fallback URL if URL params are undefined', async () => { + setItem('userId', null); + render( + + + + + + } /> +
} + /> + + + + +
, + ); + + await waitFor(() => { + expect(screen.getByTestId('paramsError')).toBeInTheDocument(); + }); + }); + + it('should render Upcoming Events screen', async () => { + renderUpcomingEvents(link1); + const searchInput = await screen.findByTestId('searchBy'); + expect(searchInput).toBeInTheDocument(); + }); + + it('Search by event title', async () => { + renderUpcomingEvents(link1); + const searchInput = await screen.findByTestId('searchBy'); + expect(searchInput).toBeInTheDocument(); + + const searchToggle = await screen.findByTestId('searchByToggle'); + expect(searchToggle).toBeInTheDocument(); + userEvent.click(searchToggle); + + const searchByTitle = await screen.findByTestId('title'); + expect(searchByTitle).toBeInTheDocument(); + userEvent.click(searchByTitle); + + userEvent.type(searchInput, '1'); + await debounceWait(); + + const eventTitle = await screen.findAllByTestId('eventTitle'); + expect(eventTitle[0]).toHaveTextContent('Event 1'); + }); + + it('Search by event location on click of search button', async () => { + renderUpcomingEvents(link1); + const searchInput = await screen.findByTestId('searchBy'); + expect(searchInput).toBeInTheDocument(); + + const searchToggle = await screen.findByTestId('searchByToggle'); + expect(searchToggle).toBeInTheDocument(); + userEvent.click(searchToggle); + + const searchByLocation = await screen.findByTestId('location'); + expect(searchByLocation).toBeInTheDocument(); + userEvent.click(searchByLocation); + + // Search by name on press of ENTER + userEvent.type(searchInput, 'M'); + await debounceWait(); + + const eventTitle = await screen.findAllByTestId('eventTitle'); + expect(eventTitle[0]).toHaveTextContent('Event 1'); + }); + + it('should render screen with No Events', async () => { + renderUpcomingEvents(link3); + + await waitFor(() => { + expect(screen.getByTestId('searchBy')).toBeInTheDocument(); + expect(screen.getByText(t.noEvents)).toBeInTheDocument(); + }); + }); + + it('Error while fetching Events data', async () => { + renderUpcomingEvents(link2); + + await waitFor(() => { + expect(screen.getByTestId('errorMsg')).toBeInTheDocument(); + }); + }); + + it('Click on Individual volunteer button', async () => { + renderUpcomingEvents(link1); + + const volunteerBtn = await screen.findAllByTestId('volunteerBtn'); + userEvent.click(volunteerBtn[0]); + + await waitFor(() => { + expect(toast.success).toHaveBeenCalledWith(t.volunteerSuccess); + }); + }); + + it('Join Volunteer Group', async () => { + renderUpcomingEvents(link1); + + const eventTitle = await screen.findAllByTestId('eventTitle'); + expect(eventTitle[0]).toHaveTextContent('Event 1'); + userEvent.click(eventTitle[0]); + + const joinGroupBtn = await screen.findAllByTestId('joinBtn'); + expect(joinGroupBtn).toHaveLength(3); + userEvent.click(joinGroupBtn[0]); + + await waitFor(() => { + expect(toast.success).toHaveBeenCalledWith(t.volunteerSuccess); + }); + }); + + it('Error on Create Volunteer Membership', async () => { + renderUpcomingEvents(link4); + + const volunteerBtn = await screen.findAllByTestId('volunteerBtn'); + userEvent.click(volunteerBtn[0]); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalled(); + }); + }); +}); diff --git a/src/screens/UserPortal/Volunteer/UpcomingEvents/UpcomingEvents.tsx b/src/screens/UserPortal/Volunteer/UpcomingEvents/UpcomingEvents.tsx new file mode 100644 index 0000000000..bd61ca97e0 --- /dev/null +++ b/src/screens/UserPortal/Volunteer/UpcomingEvents/UpcomingEvents.tsx @@ -0,0 +1,377 @@ +import React, { useMemo, useState } from 'react'; +import { Dropdown, Form, Button } from 'react-bootstrap'; +import styles from '../VolunteerManagement.module.css'; +import { useTranslation } from 'react-i18next'; +import { Navigate, useParams } from 'react-router-dom'; +import { IoLocationOutline } from 'react-icons/io5'; +import { + Paper, + Table, + TableBody, + TableCell, + TableContainer, + TableHead, + TableRow, + Accordion, + AccordionDetails, + AccordionSummary, + Chip, + Stack, + debounce, +} from '@mui/material'; +import { Circle, Search, Sort, WarningAmberRounded } from '@mui/icons-material'; + +import { GridExpandMoreIcon } from '@mui/x-data-grid'; +import useLocalStorage from 'utils/useLocalstorage'; +import { useMutation, useQuery } from '@apollo/client'; +import type { InterfaceUserEvents } from 'utils/interfaces'; +import { IoIosHand } from 'react-icons/io'; +import Loader from 'components/Loader/Loader'; +import { USER_EVENTS_VOLUNTEER } from 'GraphQl/Queries/PlugInQueries'; +import { CREATE_VOLUNTEER_MEMBERSHIP } from 'GraphQl/Mutations/EventVolunteerMutation'; +import { toast } from 'react-toastify'; +import { FaCheck } from 'react-icons/fa'; + +/** + * The `UpcomingEvents` component displays list of upcoming events for the user to volunteer. + * It allows the user to search, sort, and volunteer for events/volunteer groups. + * + * @returns The rendered component displaying the upcoming events. + */ +const UpcomingEvents = (): JSX.Element => { + // Retrieves translation functions for various namespaces + const { t } = useTranslation('translation', { + keyPrefix: 'userVolunteer', + }); + 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 ; + } + const [searchValue, setSearchValue] = useState(''); + const [searchTerm, setSearchTerm] = useState(''); + const [searchBy, setSearchBy] = useState<'title' | 'location'>('title'); + + const [createVolunteerMembership] = useMutation(CREATE_VOLUNTEER_MEMBERSHIP); + + const debouncedSearch = useMemo( + () => debounce((value: string) => setSearchTerm(value), 300), + [], + ); + + const handleVolunteer = async ( + eventId: string, + group: string | null, + status: string, + ): Promise => { + try { + await createVolunteerMembership({ + variables: { + data: { + event: eventId, + group, + status, + userId, + }, + }, + }); + toast.success(t('volunteerSuccess')); + refetchEvents(); + } catch (error) { + toast.error((error as Error).message); + } + }; + + // Fetches upcomin events based on the organization ID, search term, and sorting order + const { + data: eventsData, + loading: eventsLoading, + error: eventsError, + refetch: refetchEvents, + }: { + data?: { + eventsByOrganizationConnection: InterfaceUserEvents[]; + }; + loading: boolean; + error?: Error | undefined; + refetch: () => void; + } = useQuery(USER_EVENTS_VOLUNTEER, { + variables: { + organization_id: orgId, + title_contains: searchBy === 'title' ? searchTerm : '', + location_contains: searchBy === 'location' ? searchTerm : '', + upcomingOnly: true, + first: null, + skip: null, + }, + }); + + // Extracts the list of upcoming events from the fetched data + const events = useMemo(() => { + if (eventsData) { + return eventsData.eventsByOrganizationConnection; + } + return []; + }, [eventsData]); + + // Renders a loader while events are being fetched + if (eventsLoading) return ; + if (eventsError) { + // Displays an error message if there is an issue loading the events + return ( +
+
+ +
+ {tErrors('errorLoading', { entity: 'Events' })} +
+
+
+ ); + } + + // Renders the upcoming events list and UI elements for searching, sorting, and adding pledges + return ( + <> +
+ {/* Search input field and button */} +
+ { + setSearchValue(e.target.value); + debouncedSearch(e.target.value); + }} + data-testid="searchBy" + /> + +
+
+
+ + + + {tCommon('searchBy', { item: '' })} + + + setSearchBy('title')} + data-testid="title" + > + {t('name')} + + setSearchBy('location')} + data-testid="location" + > + {tCommon('location')} + + + +
+
+
+ {events.length < 1 ? ( + + {/* Displayed if no events are found */} + {t('noEvents')} + + ) : ( + events.map((event: InterfaceUserEvents, index: number) => { + const { + title, + description, + startDate, + endDate, + location, + volunteerGroups, + recurring, + _id, + volunteers, + } = event; + const isVolunteered = volunteers.some( + (volunteer) => volunteer.user._id === userId, + ); + return ( + + }> +
+
+
+

{title}

+ {recurring && ( + } + label={t('recurring')} + variant="outlined" + color="primary" + className={`${styles.chip} ${styles.active}`} + /> + )} +
+ +
+ + {' '} + + location: {location} + + Start Date: {startDate as unknown as string} + End Date: {endDate as unknown as string} +
+
+
+ +
+
+
+ + { + /*istanbul ignore next*/ + description && ( +
+ Description: + {description} +
+ ) + } + {volunteerGroups && volunteerGroups.length > 0 && ( + + + Volunteer Groups: + + + + + + + Sr. No. + + Group Name + + + No. of Members + + + Options + + + + + {volunteerGroups.map((group, index) => { + const { _id: gId, name, volunteers } = group; + const hasJoined = volunteers.some( + (volunteer) => volunteer._id === userId, + ); + return ( + + + {index + 1} + + + {name} + + + {volunteers.length} + + + + + + ); + })} + +
+
+
+ )} +
+
+ ); + }) + )} + + ); +}; + +export default UpcomingEvents; diff --git a/src/screens/UserPortal/Volunteer/VolunteerManagement.module.css b/src/screens/UserPortal/Volunteer/VolunteerManagement.module.css new file mode 100644 index 0000000000..d3b2bbaa54 --- /dev/null +++ b/src/screens/UserPortal/Volunteer/VolunteerManagement.module.css @@ -0,0 +1,138 @@ +/* Upcoming Events Styles */ +.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/Volunteer/VolunteerManagement.test.tsx b/src/screens/UserPortal/Volunteer/VolunteerManagement.test.tsx new file mode 100644 index 0000000000..65d2d082a7 --- /dev/null +++ b/src/screens/UserPortal/Volunteer/VolunteerManagement.test.tsx @@ -0,0 +1,128 @@ +import React from 'react'; +import type { RenderResult } from '@testing-library/react'; +import { render, screen, waitFor } from '@testing-library/react'; +import { MockedProvider } from '@apollo/react-testing'; +import { I18nextProvider } from 'react-i18next'; +import i18n from 'utils/i18nForTest'; +import { MemoryRouter, Route, Routes } from 'react-router-dom'; +import { Provider } from 'react-redux'; +import { store } from 'state/store'; +import VolunteerManagement from './VolunteerManagement'; +import userEvent from '@testing-library/user-event'; +import { MOCKS } from './UpcomingEvents/UpcomingEvents.mocks'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import useLocalStorage from 'utils/useLocalstorage'; +const { setItem } = useLocalStorage(); + +const link1 = new StaticMockLink(MOCKS); + +const renderVolunteerManagement = (): RenderResult => { + return render( + + + + + + } + /> + } /> + } + /> + + + + + , + ); +}; + +describe('Volunteer Management', () => { + beforeAll(() => { + jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ orgId: 'orgId' }), + })); + }); + + beforeEach(() => { + setItem('userId', 'userId'); + }); + + afterAll(() => { + jest.clearAllMocks(); + }); + + it('should redirect to fallback URL if URL params are undefined', async () => { + render( + + + + + + } + /> + } + /> + + + + + , + ); + + await waitFor(() => { + expect(screen.getByTestId('paramsError')).toBeInTheDocument(); + }); + }); + + test('Render Volunteer Management Screen', async () => { + renderVolunteerManagement(); + + const upcomingEventsTab = await screen.findByTestId('upcomingEventsTab'); + expect(upcomingEventsTab).toBeInTheDocument(); + expect(screen.getByTestId('invitationsBtn')).toBeInTheDocument(); + expect(screen.getByTestId('actionsBtn')).toBeInTheDocument(); + expect(screen.getByTestId('groupsBtn')).toBeInTheDocument(); + }); + + test('Testing back button navigation', async () => { + renderVolunteerManagement(); + + const backButton = await screen.findByTestId('backBtn'); + userEvent.click(backButton); + await waitFor(() => { + const orgHome = screen.getByTestId('orgHome'); + expect(orgHome).toBeInTheDocument(); + }); + }); + + test('Testing volunteer management tab switching', async () => { + renderVolunteerManagement(); + + const invitationsBtn = screen.getByTestId('invitationsBtn'); + userEvent.click(invitationsBtn); + + const invitationsTab = screen.getByTestId('invitationsTab'); + expect(invitationsTab).toBeInTheDocument(); + + const actionsBtn = screen.getByTestId('actionsBtn'); + userEvent.click(actionsBtn); + + const actionsTab = screen.getByTestId('actionsTab'); + expect(actionsTab).toBeInTheDocument(); + + const groupsBtn = screen.getByTestId('groupsBtn'); + userEvent.click(groupsBtn); + + const groupsTab = screen.getByTestId('groupsTab'); + expect(groupsTab).toBeInTheDocument(); + }); +}); diff --git a/src/screens/UserPortal/Volunteer/VolunteerManagement.tsx b/src/screens/UserPortal/Volunteer/VolunteerManagement.tsx new file mode 100644 index 0000000000..87be9d7adc --- /dev/null +++ b/src/screens/UserPortal/Volunteer/VolunteerManagement.tsx @@ -0,0 +1,211 @@ +import React, { useState } from 'react'; +import Row from 'react-bootstrap/Row'; +import Col from 'react-bootstrap/Col'; +import { Navigate, useNavigate, useParams } from 'react-router-dom'; +import { FaChevronLeft, FaTasks } from 'react-icons/fa'; +import { useTranslation } from 'react-i18next'; +import { Button, Dropdown } from 'react-bootstrap'; +import { TbCalendarEvent } from 'react-icons/tb'; +import { FaRegEnvelopeOpen, FaUserGroup } from 'react-icons/fa6'; +import UpcomingEvents from './UpcomingEvents/UpcomingEvents'; +import Invitations from './Invitations/Invitations'; +import Actions from './Actions/Actions'; +import Groups from './Groups/Groups'; + +/** + * List of tabs for the volunteer dashboard. + * + * Each tab is associated with an icon and value. + */ +const volunteerDashboardTabs: { + value: TabOptions; + icon: JSX.Element; +}[] = [ + { + value: 'upcomingEvents', + icon: , + }, + { + value: 'invitations', + icon: , + }, + { + value: 'actions', + icon: , + }, + { + value: 'groups', + icon: , + }, +]; + +/** + * Tab options for the volunteer management component. + */ +type TabOptions = 'upcomingEvents' | 'invitations' | 'actions' | 'groups'; + +/** + * `VolunteerManagement` component handles the display and navigation of different event management sections. + * + * It provides a tabbed interface for: + * - Viewing upcoming events to volunteer + * - Managing volunteer requests + * - Managing volunteer invitations + * - Managing volunteer groups + * + * @returns JSX.Element - The `VolunteerManagement` component. + */ +const VolunteerManagement = (): JSX.Element => { + // Translation hook for internationalization + const { t } = useTranslation('translation', { + keyPrefix: 'userVolunteer', + }); + + // Extract organization ID from URL parameters + const { orgId } = useParams(); + + if (!orgId) { + return ; + } + + // Hook for navigation + const navigate = useNavigate(); + + // State hook for managing the currently selected tab + const [tab, setTab] = useState('upcomingEvents'); + + /** + * 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, + }: { + value: TabOptions; + icon: React.ReactNode; + }): JSX.Element => { + const selected = tab === value; + const variant = selected ? 'success' : 'light'; + const translatedText = t(value); + + const className = selected + ? 'px-4 d-flex align-items-center rounded-3 shadow-sm' + : 'text-secondary bg-white px-4 d-flex align-items-center rounded-3 shadow-sm'; + const props = { + variant, + className, + style: { height: '2.5rem' }, + onClick: () => setTab(value), + 'data-testid': `${value}Btn`, + }; + + return ( + + ); + }; + + const handleBack = (): void => { + navigate(`/user/organization/${orgId}`); + }; + + return ( +
+ + +
+ + {volunteerDashboardTabs.map(renderButton)} +
+ + + + {t(tab)} + + + {/* Render dropdown items for each settings category */} + {volunteerDashboardTabs.map(({ value, icon }, index) => ( + setTab(value) + } + className={`d-flex gap-2 ${tab === value && 'text-secondary'}`} + > + {icon} {t(value)} + + ))} + + + + + +
+
+
+ + {/* Render content based on the selected settings category */} + {(() => { + switch (tab) { + case 'upcomingEvents': + return ( +
+ +
+ ); + case 'invitations': + return ( +
+ +
+ ); + case 'actions': + return ( +
+ +
+ ); + case 'groups': + return ( +
+ +
+ ); + } + })()} +
+ ); +}; + +export default VolunteerManagement; diff --git a/src/screens/Users/Users.module.css b/src/screens/Users/Users.module.css deleted file mode 100644 index 0750dba108..0000000000 --- a/src/screens/Users/Users.module.css +++ /dev/null @@ -1,95 +0,0 @@ -.btnsContainer { - display: flex; - margin: 2.5rem 0 2.5rem 0; -} - -.btnsContainer .btnsBlock { - display: flex; -} - -.btnsContainer .btnsBlock button { - margin-left: 1rem; - display: flex; - justify-content: center; - align-items: center; -} - -.btnsContainer .inputContainer { - flex: 1; - position: relative; -} -.btnsContainer .input { - width: 70%; - position: relative; -} - -.btnsContainer input { - outline: 1px solid var(--bs-gray-400); -} - -.btnsContainer .inputContainer button { - width: 52px; -} - -.listBox { - width: 100%; - flex: 1; -} - -.notFound { - flex: 1; - display: flex; - justify-content: center; - align-items: center; - flex-direction: column; -} - -@media (max-width: 1020px) { - .btnsContainer { - flex-direction: column; - margin: 1.5rem 0; - } - .btnsContainer .input { - width: 100%; - } - .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%; - } -} diff --git a/src/screens/Users/Users.spec.tsx b/src/screens/Users/Users.spec.tsx new file mode 100644 index 0000000000..1457bec5b8 --- /dev/null +++ b/src/screens/Users/Users.spec.tsx @@ -0,0 +1,1553 @@ +import React from 'react'; +import { MockedProvider } from '@apollo/react-testing'; +import { act, fireEvent, render, screen } from '@testing-library/react'; +import { I18nextProvider } from 'react-i18next'; +import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; +import { ToastContainer } from 'react-toastify'; +import userEvent from '@testing-library/user-event'; +import { store } from 'state/store'; +import { StaticMockLink } from 'utils/StaticMockLink'; +import i18nForTest from 'utils/i18nForTest'; +import Users from './Users'; +import { EMPTY_MOCKS, MOCKS, MOCKS2 } from './UsersMocks'; +import useLocalStorage from 'utils/useLocalstorage'; +import { describe, expect, it, beforeEach, afterEach, vi } from 'vitest'; + +import { + USER_LIST, + ORGANIZATION_CONNECTION_LIST, +} from 'GraphQl/Queries/Queries'; + +const { setItem, removeItem } = useLocalStorage(); + +const createAddress = { + city: 'Kingston', + countryCode: 'JM', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Jamaica Street', + line2: 'Apartment 456', + postalCode: 'JM12345', + sortingCode: 'ABC-123', + state: 'Kingston Parish', +}; + +const createCreator = { + _id: '123', + firstName: 'Jack', + lastName: 'Smith', + image: null, + email: 'jack@example.com', + createdAt: '19/06/2022', +}; + +const MOCK_USERS = [ + { + user: { + _id: 'user1', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + createdAt: '2023-04-13T04:53:17.742+00:00', + registeredEvents: [], + membershipRequests: [], + organizationsBlockedBy: [ + { + _id: 'xyz', + name: 'ABC', + image: null, + address: createAddress, + createdAt: '20/06/2022', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + createdAt: '20/06/2022', + }, + }, + ], + joinedOrganizations: [ + { + _id: 'abc', + name: 'Joined Organization 1', + image: null, + address: createAddress, + createdAt: '20/06/2022', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + createdAt: '20/06/2022', + }, + }, + ], + }, + appUserProfile: { + _id: 'user1', + adminFor: [ + { + _id: '123', + }, + ], + isSuperAdmin: true, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + }, + }, + { + user: { + _id: 'user2', + firstName: 'Jane', + lastName: 'Doe', + image: null, + email: 'john@example.com', + createdAt: '2023-04-17T04:53:17.742+00:00', + registeredEvents: [], + membershipRequests: [], + organizationsBlockedBy: [ + { + _id: '456', + name: 'ABC', + image: null, + address: createAddress, + createdAt: '21/06/2022', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + createdAt: '21/06/2022', + }, + }, + ], + joinedOrganizations: [ + { + _id: '123', + name: 'Palisadoes', + image: null, + address: createAddress, + createdAt: '21/06/2022', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + createdAt: '21/06/2022', + }, + }, + ], + }, + appUserProfile: { + _id: 'user2', + adminFor: [ + { + _id: '123', + }, + ], + isSuperAdmin: false, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + }, + }, + { + user: { + _id: 'user3', + firstName: 'Jack', + lastName: 'Smith', + image: null, + email: 'jack@example.com', + createdAt: '2023-04-09T04:53:17.742+00:00', + registeredEvents: [], + membershipRequests: [], + organizationsBlockedBy: [ + { + _id: 'xyz', + name: 'ABC', + image: null, + address: createAddress, + createdAt: '19/06/2022', + creator: createCreator, + }, + ], + joinedOrganizations: [ + { + _id: 'abc', + name: 'Joined Organization 1', + image: null, + address: createAddress, + createdAt: '19/06/2022', + creator: createCreator, + }, + ], + }, + appUserProfile: { + _id: 'user3', + adminFor: [], + isSuperAdmin: false, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + }, + }, +]; + +const MOCK_USERS2 = [ + ...MOCK_USERS, + { + user: { + _id: 'user4', + firstName: 'Emma', + lastName: 'Johnson', + image: null, + email: 'emma@example.com', + createdAt: '2023-04-22T04:53:17.742+00:00', + registeredEvents: [], + membershipRequests: [], + organizationsBlockedBy: [ + { + _id: 'xyz', + name: 'ABC', + image: null, + address: createAddress, + createdAt: '19/06/2022', + creator: createCreator, + }, + ], + joinedOrganizations: [ + { + _id: 'abc', + name: 'Joined Organization 1', + image: null, + address: createAddress, + createdAt: '19/06/2022', + creator: createCreator, + }, + ], + }, + appUserProfile: { + _id: 'user4', + adminFor: [], + isSuperAdmin: false, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + }, + }, + { + user: { + _id: 'user5', + firstName: 'Liam', + lastName: 'Smith', + image: null, + email: 'liam@example.com', + createdAt: '2023-04-23T04:53:17.742+00:00', + registeredEvents: [], + membershipRequests: [], + organizationsBlockedBy: [ + { + _id: 'xyz', + name: 'ABC', + image: null, + address: createAddress, + createdAt: '19/06/2022', + creator: createCreator, + }, + ], + joinedOrganizations: [ + { + _id: 'abc', + name: 'Joined Organization 1', + image: null, + address: createAddress, + createdAt: '19/06/2022', + creator: createCreator, + }, + ], + }, + appUserProfile: { + _id: 'user5', + adminFor: [], + isSuperAdmin: false, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + }, + }, + { + user: { + _id: 'user6', + firstName: 'Olivia', + lastName: 'Brown', + image: null, + email: 'olivia@example.com', + createdAt: '2023-04-24T04:53:17.742+00:00', + registeredEvents: [], + membershipRequests: [], + organizationsBlockedBy: [ + { + _id: 'xyz', + name: 'ABC', + image: null, + address: createAddress, + createdAt: '19/06/2022', + creator: createCreator, + }, + ], + joinedOrganizations: [ + { + _id: 'abc', + name: 'Joined Organization 1', + image: null, + address: createAddress, + createdAt: '19/06/2022', + creator: createCreator, + }, + ], + }, + appUserProfile: { + _id: 'user6', + adminFor: [], + isSuperAdmin: false, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + }, + }, + { + user: { + _id: 'user7', + firstName: 'Noah', + lastName: 'Williams', + image: null, + email: 'noah@example.com', + createdAt: '2023-04-25T04:53:17.742+00:00', + registeredEvents: [], + membershipRequests: [], + organizationsBlockedBy: [ + { + _id: 'xyz', + name: 'ABC', + image: null, + address: createAddress, + createdAt: '19/06/2022', + creator: createCreator, + }, + ], + joinedOrganizations: [ + { + _id: 'abc', + name: 'Joined Organization 1', + image: null, + address: createAddress, + createdAt: '19/06/2022', + creator: createCreator, + }, + ], + }, + appUserProfile: { + _id: 'user7', + adminFor: [], + isSuperAdmin: false, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + }, + }, + { + user: { + _id: 'user8', + firstName: 'Ava', + lastName: 'Jones', + image: null, + email: 'ava@example.com', + createdAt: '2023-04-26T04:53:17.742+00:00', + registeredEvents: [], + membershipRequests: [], + organizationsBlockedBy: [ + { + _id: 'xyz', + name: 'ABC', + image: null, + address: createAddress, + createdAt: '19/06/2022', + creator: createCreator, + }, + ], + joinedOrganizations: [ + { + _id: 'abc', + name: 'Joined Organization 1', + image: null, + address: createAddress, + createdAt: '19/06/2022', + creator: createCreator, + }, + ], + }, + appUserProfile: { + _id: 'user8', + adminFor: [], + isSuperAdmin: false, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + }, + }, + { + user: { + _id: 'user9', + firstName: 'Ethan', + lastName: 'Garcia', + image: null, + email: 'ethan@example.com', + createdAt: '2023-04-27T04:53:17.742+00:00', + registeredEvents: [], + membershipRequests: [], + organizationsBlockedBy: [ + { + _id: 'xyz', + name: 'ABC', + image: null, + address: createAddress, + createdAt: '19/06/2022', + creator: createCreator, + }, + ], + joinedOrganizations: [ + { + _id: 'abc', + name: 'Joined Organization 1', + image: null, + address: createAddress, + createdAt: '19/06/2022', + creator: createCreator, + }, + ], + }, + appUserProfile: { + _id: 'user9', + adminFor: [], + isSuperAdmin: false, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + }, + }, + { + user: { + _id: 'user10', + firstName: 'Sophia', + lastName: 'Martinez', + image: null, + email: 'sophia@example.com', + createdAt: '2023-04-28T04:53:17.742+00:00', + registeredEvents: [], + membershipRequests: [], + organizationsBlockedBy: [ + { + _id: 'xyz', + name: 'ABC', + image: null, + address: createAddress, + createdAt: '19/06/2022', + creator: createCreator, + }, + ], + joinedOrganizations: [ + { + _id: 'abc', + name: 'Joined Organization 1', + image: null, + address: createAddress, + createdAt: '19/06/2022', + creator: createCreator, + }, + ], + }, + appUserProfile: { + _id: 'user10', + adminFor: [], + isSuperAdmin: false, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + }, + }, + { + user: { + _id: 'user11', + firstName: 'Mason', + lastName: 'Davis', + image: null, + email: 'mason@example.com', + createdAt: '2023-04-29T04:53:17.742+00:00', + registeredEvents: [], + membershipRequests: [], + organizationsBlockedBy: [ + { + _id: 'xyz', + name: 'ABC', + image: null, + address: createAddress, + createdAt: '19/06/2022', + creator: createCreator, + }, + ], + joinedOrganizations: [ + { + _id: 'abc', + name: 'Joined Organization 1', + image: null, + address: createAddress, + createdAt: '19/06/2022', + creator: createCreator, + }, + ], + }, + appUserProfile: { + _id: 'user11', + adminFor: [], + isSuperAdmin: false, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + }, + }, + { + user: { + _id: 'user12', + firstName: 'Isabella', + lastName: 'Rodriguez', + image: null, + email: 'isabella@example.com', + createdAt: '2023-04-30T04:53:17.742+00:00', + registeredEvents: [], + membershipRequests: [], + organizationsBlockedBy: [ + { + _id: 'xyz', + name: 'ABC', + image: null, + address: createAddress, + createdAt: '19/06/2022', + creator: createCreator, + }, + ], + joinedOrganizations: [ + { + _id: 'abc', + name: 'Joined Organization 1', + image: null, + address: createAddress, + createdAt: '19/06/2022', + creator: createCreator, + }, + ], + }, + appUserProfile: { + _id: 'user12', + adminFor: [], + isSuperAdmin: false, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + }, + }, + { + user: { + _id: 'user13', + firstName: 'Logan', + lastName: 'Wilson', + image: null, + email: 'logan@example.com', + createdAt: '2023-04-08T04:53:17.742+00:00', + registeredEvents: [], + membershipRequests: [], + organizationsBlockedBy: [ + { + _id: 'xyz', + name: 'ABC', + image: null, + address: createAddress, + createdAt: '19/06/2022', + creator: createCreator, + }, + ], + joinedOrganizations: [ + { + _id: 'abc', + name: 'Joined Organization 1', + image: null, + address: createAddress, + createdAt: '19/06/2022', + creator: createCreator, + }, + ], + }, + appUserProfile: { + _id: 'user13', + adminFor: [], + isSuperAdmin: false, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + }, + }, + { + user: { + _id: 'user14', + firstName: 'Mia', + lastName: 'Anderson', + image: null, + email: 'mia@example.com', + createdAt: '2023-04-07T04:53:17.742+00:00', + registeredEvents: [], + membershipRequests: [], + organizationsBlockedBy: [ + { + _id: 'xyz', + name: 'ABC', + image: null, + address: createAddress, + createdAt: '19/06/2022', + creator: createCreator, + }, + ], + joinedOrganizations: [ + { + _id: 'abc', + name: 'Joined Organization 1', + image: null, + address: createAddress, + createdAt: '19/06/2022', + creator: createCreator, + }, + ], + }, + appUserProfile: { + _id: 'user14', + adminFor: [], + isSuperAdmin: false, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + }, + }, + { + user: { + _id: 'user15', + firstName: 'Lucas', + lastName: 'Thomas', + image: null, + email: 'lucas@example.com', + createdAt: '2023-04-05T04:53:17.742+00:00', + registeredEvents: [], + membershipRequests: [], + organizationsBlockedBy: [ + { + _id: 'xyz', + name: 'ABC', + image: null, + address: createAddress, + createdAt: '19/06/2022', + creator: createCreator, + }, + ], + joinedOrganizations: [ + { + _id: 'abc', + name: 'Joined Organization 1', + image: null, + address: createAddress, + createdAt: '19/06/2022', + creator: createCreator, + }, + ], + }, + appUserProfile: { + _id: 'user15', + adminFor: [], + isSuperAdmin: false, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + }, + }, +]; + +const MOCKS_NEW = [ + { + request: { + query: USER_LIST, + variables: { + first: 12, + skip: 0, + firstName_contains: '', + lastName_contains: '', + order: 'createdAt_DESC', + }, + }, + result: { + data: { + users: MOCK_USERS, + }, + }, + }, + { + request: { + query: ORGANIZATION_CONNECTION_LIST, + }, + result: { + data: { + organizationsConnection: [], + }, + }, + }, +]; + +const MOCKS_NEW2 = [ + { + request: { + query: USER_LIST, + variables: { + first: 12, + skip: 0, + firstName_contains: '', + lastName_contains: '', + order: 'createdAt_DESC', + }, + }, + result: { + data: { + users: MOCK_USERS2.slice(0, 12), + }, + }, + }, + { + request: { + query: ORGANIZATION_CONNECTION_LIST, + }, + result: { + data: { + organizationsConnection: [], + }, + }, + }, + { + request: { + query: USER_LIST, + variables: { + first: 24, + skip: 0, + firstName_contains: '', + lastName_contains: '', + order: 'createdAt_DESC', + filter: '', + }, + }, + result: { + data: { + users: MOCK_USERS2.slice(12, 15), + }, + }, + }, +]; + +const MOCKS_NEW3 = [ + { + request: { + query: USER_LIST, + variables: { + first: 12, + skip: 0, + firstName_contains: '', + lastName_contains: '', + order: 'createdAt_DESC', + }, + }, + result: { + data: { + users: MOCK_USERS2.slice(0, 12), + }, + }, + }, + { + request: { + query: ORGANIZATION_CONNECTION_LIST, + }, + result: { + data: { + organizationsConnection: [], + }, + }, + }, + { + request: { + query: USER_LIST, + variables: { + first: 24, + skip: 0, + firstName_contains: '', + lastName_contains: '', + order: 'createdAt_DESC', + filter: '', + }, + }, + result: { + data: { + users: MOCK_USERS2.slice(11, 15), + }, + }, + }, + { + request: { + query: USER_LIST, + variables: { + first: 24, + skip: 0, + firstName_contains: '', + lastName_contains: '', + order: 'createdAt_DESC', + filter: '', + }, + }, + result: { + data: { + users: MOCK_USERS2.slice(11, 15), + }, + }, + }, + { + request: { + query: USER_LIST, + variables: { + first: 13, + skip: 3, + firstName_contains: '', + lastName_contains: '', + order: 'createdAt_DESC', + filter: '', + }, + }, + result: { + data: { + users: [], + }, + }, + }, +]; + +const link = new StaticMockLink(MOCKS, true); +const link2 = new StaticMockLink(EMPTY_MOCKS, true); +const link3 = new StaticMockLink(MOCKS2, true); +const link5 = new StaticMockLink(MOCKS_NEW, true); +const link6 = new StaticMockLink(MOCKS_NEW2, true); +const link7 = new StaticMockLink(MOCKS_NEW3, true); + +async function wait(ms = 1000): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} +beforeEach(() => { + setItem('id', '123'); + setItem('SuperAdmin', true); + setItem('FirstName', 'John'); + setItem('AdminFor', [{ name: 'adi', _id: '1234', image: '' }]); + setItem('LastName', 'Doe'); +}); + +afterEach(() => { + localStorage.clear(); + vi.restoreAllMocks(); +}); + +describe('Testing Users screen', () => { + it('Component should be rendered properly', async () => { + render( + + + + + + + + + , + ); + + await wait(); + expect(screen.getByTestId('testcomp')).toBeInTheDocument(); + }); + + it(`Component should be rendered properly when user is not superAdmin + and or userId does not exists in localstorage`, async () => { + setItem('AdminFor', ['123']); + removeItem('SuperAdmin'); + await wait(); + setItem('id', ''); + render( + + + + + + + + + , + ); + await wait(); + }); + + it(`Component should be rendered properly when userId does not exists in localstorage`, async () => { + removeItem('AdminFor'); + removeItem('SuperAdmin'); + await wait(); + removeItem('id'); + render( + + + + + + + + + , + ); + await wait(); + }); + + it('Component should be rendered properly when user is superAdmin', async () => { + render( + + + + + + + + + , + ); + + await wait(); + }); + + it('Testing seach by name functionality', async () => { + render( + + + + + + + + + , + ); + + await wait(); + const searchBtn = screen.getByTestId('searchButton'); + const search1 = 'John'; + userEvent.type(screen.getByTestId(/searchByName/i), search1); + userEvent.click(searchBtn); + await wait(); + expect(screen.queryByText(/not found/i)).not.toBeInTheDocument(); + + const search2 = 'Pete{backspace}{backspace}{backspace}{backspace}'; + userEvent.type(screen.getByTestId(/searchByName/i), search2); + + const search3 = + 'John{backspace}{backspace}{backspace}{backspace}Sam{backspace}{backspace}{backspace}'; + userEvent.type(screen.getByTestId(/searchByName/i), search3); + + const search4 = 'Sam{backspace}{backspace}P{backspace}'; + userEvent.type(screen.getByTestId(/searchByName/i), search4); + + const search5 = 'Xe'; + userEvent.type(screen.getByTestId(/searchByName/i), search5); + userEvent.clear(screen.getByTestId(/searchByName/i)); + userEvent.type(screen.getByTestId(/searchByName/i), ''); + userEvent.click(searchBtn); + await wait(); + }); + + it('testing search not found', async () => { + await act(async () => { + render( + + + + + + + + + , + ); + }); + await wait(); + + 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(); + }); + + it('Testing User data is not present', async () => { + render( + + + + + + + + + , + ); + + await wait(); + expect(screen.getByText(/No User Found/i)).toBeTruthy(); + }); + + it('Should render warning alert when there are no organizations', async () => { + const { container } = render( + + + + + + + + + + , + ); + + await wait(200); + expect(container.textContent).toMatch( + 'Organizations not found, please create an organization through dashboard', + ); + }); + + it('Should not render warning alert when there are organizations present', async () => { + const { container } = render( + + + + + + + + + + , + ); + + await wait(); + + expect(container.textContent).not.toMatch( + 'Organizations not found, please create an organization through dashboard', + ); + }); + + it('Testing filter functionality', async () => { + await act(async () => { + render( + + + + + + + + + + , + ); + }); + await wait(); + + const searchInput = screen.getByTestId('filter'); + expect(searchInput).toBeInTheDocument(); + + const inputText = screen.getByTestId('filterUsers'); + + await act(async () => { + fireEvent.click(inputText); + }); + + const toggleText = screen.getByTestId('admin'); + + await act(async () => { + fireEvent.click(toggleText); + }); + + expect(searchInput).toBeInTheDocument(); + + await act(async () => { + fireEvent.click(inputText); + }); + + let toggleTite = screen.getByTestId('superAdmin'); + + await act(async () => { + fireEvent.click(toggleTite); + }); + + expect(searchInput).toBeInTheDocument(); + + await act(async () => { + fireEvent.click(inputText); + }); + + toggleTite = screen.getByTestId('user'); + + await act(async () => { + fireEvent.click(toggleTite); + }); + + expect(searchInput).toBeInTheDocument(); + + await act(async () => { + fireEvent.click(inputText); + }); + + toggleTite = screen.getByTestId('cancel'); + + await act(async () => { + fireEvent.click(toggleTite); + }); + + await wait(); + + expect(searchInput).toBeInTheDocument(); + }); + + it('check for rerendering', async () => { + const { rerender } = render( + + + + + + + + + + , + ); + + await wait(); + rerender( + + + + + + + + + + , + ); + await wait(); + }); + + it('should set hasMore to false if users length is less than perPageResult', async () => { + const link = new StaticMockLink(EMPTY_MOCKS, true); + + render( + + + + + + + + + + , + ); + + await wait(200); + + // Check if "No User Found" is displayed + expect(screen.getByText(/No User Found/i)).toBeInTheDocument(); + }); + + it('should filter users correctly', async () => { + await act(async () => { + render( + + + + + + + + + + , + ); + }); + await wait(); + + const filterButton = screen.getByTestId('filterUsers'); + + await act(async () => { + fireEvent.click(filterButton); + }); + + const filterAdmin = screen.getByTestId('admin'); + + await act(async () => { + fireEvent.click(filterAdmin); + }); + + // await wait(); + expect(screen.getByText('Jane Doe')).toBeInTheDocument(); + + await act(async () => { + fireEvent.click(filterButton); + }); + + const filterSuperAdmin = screen.getByTestId('superAdmin'); + + await act(async () => { + fireEvent.click(filterSuperAdmin); + }); + + // await wait(); + expect(screen.getByText('John Doe')).toBeInTheDocument(); + + await act(async () => { + fireEvent.click(filterButton); + }); + + const filterUser = screen.getByTestId('user'); + await act(async () => { + fireEvent.click(filterUser); + }); + + // await wait(); + expect(screen.getByText('Jack Smith')).toBeInTheDocument(); + + await act(async () => { + fireEvent.click(filterButton); + }); + + 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(); + }); + + it('Users should be sorted in newest order correctly', async () => { + await act(async () => { + render( + + + + + + + + + + , + ); + }); + await wait(); + + const inputText = screen.getByTestId('sortUsers'); + + await act(async () => { + fireEvent.click(inputText); + }); + + const toggleTite = screen.getByTestId('newest'); + + await act(async () => { + fireEvent.click(toggleTite); + }); + + // Verify the users are sorted by newest + + const displayedUsers = screen.getAllByRole('row'); + await wait(); + expect(displayedUsers[1]).toHaveTextContent('Jane Doe'); + expect(displayedUsers[2]).toHaveTextContent('John Doe'); + }); + + it('Check if pressing enter key triggers search', async () => { + await act(async () => { + render( + + + + + + + + + + , + ); + }); + await wait(); + const searchInput = screen.getByTestId('searchByName'); + + await act(async () => { + userEvent.type(searchInput, 'John'); + }); + await act(async () => { + userEvent.type(searchInput, '{enter}'); + }); + }); + + it('Users should be sorted in oldest order correctly', async () => { + await act(async () => { + render( + + + + + + + + + + , + ); + }); + await wait(); + + const inputText = screen.getByTestId('sortUsers'); + + await act(async () => { + fireEvent.click(inputText); + }); + + const toggleTite = screen.getByTestId('oldest'); + + await act(async () => { + fireEvent.click(toggleTite); + }); + + // Verify the users are sorted by oldest + + const displayedUsers = screen.getAllByRole('row'); + await wait(); + expect(displayedUsers[1]).toHaveTextContent('Jack Smith'); + expect(displayedUsers[2]).toHaveTextContent('John Doe'); + }); + + it('Role filter should not update if selected role is already selected', async () => { + await act(async () => { + render( + + + + + + + + + + , + ); + }); + await wait(); + + const filterButton = screen.getByTestId('filterUsers'); + + await act(async () => { + fireEvent.click(filterButton); + }); + + const filterAdmin = screen.getByTestId('admin'); + + await act(async () => { + fireEvent.click(filterAdmin); + }); + + // await wait(); + expect(screen.getByText('Jane Doe')).toBeInTheDocument(); + + await act(async () => { + fireEvent.click(filterAdmin); + }); + + // await wait(); + expect(screen.getByText('Jane Doe')).toBeInTheDocument(); + }); + + it('Sort filter should not update if selected sort is already selected', async () => { + await act(async () => { + render( + + + + + + + + + + , + ); + }); + await wait(); + + const inputText = screen.getByTestId('sortUsers'); + + await act(async () => { + fireEvent.click(inputText); + }); + + const toggleTite = screen.getByTestId('newest'); + + await act(async () => { + fireEvent.click(toggleTite); + }); + + // Verify the users are sorted by newest + + const displayedUsers = screen.getAllByRole('row'); + await wait(); + expect(displayedUsers[1]).toHaveTextContent('Jane Doe'); + expect(displayedUsers[2]).toHaveTextContent('John Doe'); + + await act(async () => { + fireEvent.click(inputText); + }); + + const toggleTite2 = screen.getByTestId('newest'); + + await act(async () => { + fireEvent.click(toggleTite2); + }); + + // Verify the users are sorted by newest + + const displayedUsers2 = screen.getAllByRole('row'); + await wait(); + expect(displayedUsers2[1]).toHaveTextContent('Jane Doe'); + expect(displayedUsers2[2]).toHaveTextContent('John Doe'); + }); + + it('Reset and Refetch function should work when we search an empty string', async () => { + render( + + + + + + + + + , + ); + + await wait(); + const searchBtn = screen.getByTestId('searchButton'); + const search1 = ''; + userEvent.type(screen.getByTestId(/searchByName/i), search1); + userEvent.click(searchBtn); + await wait(); + expect(screen.queryByText(/Jane Doe/i)).toBeInTheDocument(); + expect(screen.queryByText(/John Doe/i)).toBeInTheDocument(); + expect(screen.queryByText(/Jack Smith/i)).toBeInTheDocument(); + }); + + it('Users should be loaded on scroll using loadmoreusers function', async () => { + const { container } = render( + + + + + + + + + , + ); + + await wait(); + const users = container + .getElementsByTagName('tbody')[0] + .querySelectorAll('tr'); + expect(users.length).toBe(12); + + await act(async () => { + fireEvent.scroll(window, { target: { scrollY: 1000 } }); + }); + + await wait(); + + const users2 = container + .getElementsByTagName('tbody')[0] + .querySelectorAll('tr'); + expect(users2.length).toBe(15); + }); + + it('should not show duplicate users when scrolling by using mergedUsers and loadUnqUsers', async () => { + const { container } = render( + + + + + + + + + , + ); + + await wait(); + const users = container + .getElementsByTagName('tbody')[0] + .querySelectorAll('tr'); + expect(users.length).toBe(12); + + await act(async () => { + fireEvent.scroll(window, { target: { scrollY: 1000 } }); + }); + + await wait(); + + const users2 = container + .getElementsByTagName('tbody')[0] + .querySelectorAll('tr'); + expect(users2.length).toBe(15); + }); +}); diff --git a/src/screens/Users/Users.test.tsx b/src/screens/Users/Users.test.tsx deleted file mode 100644 index 65558e6ea7..0000000000 --- a/src/screens/Users/Users.test.tsx +++ /dev/null @@ -1,778 +0,0 @@ -import React from 'react'; -import { MockedProvider } from '@apollo/react-testing'; -import { act, fireEvent, render, screen } from '@testing-library/react'; -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 userEvent from '@testing-library/user-event'; -import { store } from 'state/store'; -import { StaticMockLink } from 'utils/StaticMockLink'; -import i18nForTest from 'utils/i18nForTest'; -import Users from './Users'; -import { EMPTY_MOCKS, MOCKS, MOCKS2 } from './UsersMocks'; -import useLocalStorage from 'utils/useLocalstorage'; - -import { - USER_LIST, - ORGANIZATION_CONNECTION_LIST, -} from 'GraphQl/Queries/Queries'; - -const { setItem, removeItem } = useLocalStorage(); - -const MOCK_USERS = [ - { - user: { - _id: 'user1', - firstName: 'John', - lastName: 'Doe', - image: null, - email: 'john@example.com', - createdAt: '20/06/2022', - registeredEvents: [], - membershipRequests: [], - organizationsBlockedBy: [ - { - _id: 'xyz', - name: 'ABC', - image: null, - address: { - city: 'Kingston', - countryCode: 'JM', - dependentLocality: 'Sample Dependent Locality', - line1: '123 Jamaica Street', - line2: 'Apartment 456', - postalCode: 'JM12345', - sortingCode: 'ABC-123', - state: 'Kingston Parish', - }, - createdAt: '20/06/2022', - creator: { - _id: '123', - firstName: 'John', - lastName: 'Doe', - image: null, - email: 'john@example.com', - createdAt: '20/06/2022', - }, - }, - ], - joinedOrganizations: [ - { - _id: 'abc', - name: 'Joined Organization 1', - image: null, - address: { - city: 'Kingston', - countryCode: 'JM', - dependentLocality: 'Sample Dependent Locality', - line1: '123 Jamaica Street', - line2: 'Apartment 456', - postalCode: 'JM12345', - sortingCode: 'ABC-123', - state: 'Kingston Parish', - }, - createdAt: '20/06/2022', - creator: { - _id: '123', - firstName: 'John', - lastName: 'Doe', - image: null, - email: 'john@example.com', - createdAt: '20/06/2022', - }, - }, - ], - }, - appUserProfile: { - _id: 'user1', - adminFor: [ - { - _id: '123', - }, - ], - isSuperAdmin: true, - createdOrganizations: [], - createdEvents: [], - eventAdmin: [], - }, - }, - { - user: { - _id: 'user2', - firstName: 'Jane', - lastName: 'Doe', - image: null, - email: 'john@example.com', - createdAt: '21/06/2022', - registeredEvents: [], - membershipRequests: [], - organizationsBlockedBy: [ - { - _id: '456', - name: 'ABC', - image: null, - address: { - city: 'Kingston', - countryCode: 'JM', - dependentLocality: 'Sample Dependent Locality', - line1: '123 Jamaica Street', - line2: 'Apartment 456', - postalCode: 'JM12345', - sortingCode: 'ABC-123', - state: 'Kingston Parish', - }, - createdAt: '21/06/2022', - creator: { - _id: '123', - firstName: 'John', - lastName: 'Doe', - image: null, - email: 'john@example.com', - createdAt: '21/06/2022', - }, - }, - ], - joinedOrganizations: [ - { - _id: '123', - name: 'Palisadoes', - image: null, - address: { - city: 'Kingston', - countryCode: 'JM', - dependentLocality: 'Sample Dependent Locality', - line1: '123 Jamaica Street', - line2: 'Apartment 456', - postalCode: 'JM12345', - sortingCode: 'ABC-123', - state: 'Kingston Parish', - }, - createdAt: '21/06/2022', - creator: { - _id: '123', - firstName: 'John', - lastName: 'Doe', - image: null, - email: 'john@example.com', - createdAt: '21/06/2022', - }, - }, - ], - }, - appUserProfile: { - _id: 'user2', - adminFor: [ - { - _id: '123', - }, - ], - isSuperAdmin: false, - createdOrganizations: [], - createdEvents: [], - eventAdmin: [], - }, - }, - { - user: { - _id: 'user3', - firstName: 'Jack', - lastName: 'Smith', - image: null, - email: 'jack@example.com', - createdAt: '19/06/2022', - registeredEvents: [], - membershipRequests: [], - organizationsBlockedBy: [ - { - _id: 'xyz', - name: 'ABC', - image: null, - address: { - city: 'Kingston', - countryCode: 'JM', - dependentLocality: 'Sample Dependent Locality', - line1: '123 Jamaica Street', - line2: 'Apartment 456', - postalCode: 'JM12345', - sortingCode: 'ABC-123', - state: 'Kingston Parish', - }, - createdAt: '19/06/2022', - creator: { - _id: '123', - firstName: 'Jack', - lastName: 'Smith', - image: null, - email: 'jack@example.com', - createdAt: '19/06/2022', - }, - }, - ], - joinedOrganizations: [ - { - _id: 'abc', - name: 'Joined Organization 1', - image: null, - address: { - city: 'Kingston', - countryCode: 'JM', - dependentLocality: 'Sample Dependent Locality', - line1: '123 Jamaica Street', - line2: 'Apartment 456', - postalCode: 'JM12345', - sortingCode: 'ABC-123', - state: 'Kingston Parish', - }, - createdAt: '19/06/2022', - creator: { - _id: '123', - firstName: 'Jack', - lastName: 'Smith', - image: null, - email: 'jack@example.com', - createdAt: '19/06/2022', - }, - }, - ], - }, - appUserProfile: { - _id: 'user3', - adminFor: [], - isSuperAdmin: false, - createdOrganizations: [], - createdEvents: [], - eventAdmin: [], - }, - }, -]; - -const MOCKS_NEW = [ - { - request: { - query: USER_LIST, - variables: { - first: 12, - skip: 0, - firstName_contains: '', - lastName_contains: '', - order: 'createdAt_DESC', - }, - }, - result: { - data: { - users: MOCK_USERS, - }, - }, - }, - { - request: { - query: ORGANIZATION_CONNECTION_LIST, - }, - result: { - data: { - organizationsConnection: [], - }, - }, - }, -]; - -const link = new StaticMockLink(MOCKS, true); -const link2 = new StaticMockLink(EMPTY_MOCKS, true); -const link3 = new StaticMockLink(MOCKS2, true); -const link5 = new StaticMockLink(MOCKS_NEW, true); - -async function wait(ms = 1000): Promise { - await act(() => { - return new Promise((resolve) => { - setTimeout(resolve, ms); - }); - }); -} -beforeEach(() => { - setItem('id', '123'); - setItem('SuperAdmin', true); - setItem('FirstName', 'John'); - setItem('AdminFor', [{ name: 'adi', _id: '1234', image: '' }]); - setItem('LastName', 'Doe'); -}); - -afterEach(() => { - localStorage.clear(); -}); - -describe('Testing Users screen', () => { - test('Component should be rendered properly', async () => { - render( - - - - - - - - - , - ); - - await wait(); - expect(screen.getByTestId('testcomp')).toBeInTheDocument(); - }); - - test(`Component should be rendered properly when user is not superAdmin - and or userId does not exists in localstorage`, async () => { - setItem('AdminFor', ['123']); - removeItem('SuperAdmin'); - await wait(); - setItem('id', ''); - render( - - - - - - - - - , - ); - await wait(); - }); - - test(`Component should be rendered properly when userId does not exists in localstorage`, async () => { - removeItem('AdminFor'); - removeItem('SuperAdmin'); - await wait(); - removeItem('id'); - render( - - - - - - - - - , - ); - await wait(); - }); - - test('Component should be rendered properly when user is superAdmin', async () => { - render( - - - - - - - - - , - ); - - await wait(); - }); - - test('Testing seach by name functionality', async () => { - render( - - - - - - - - - , - ); - - await wait(); - const searchBtn = screen.getByTestId('searchButton'); - const search1 = 'John'; - userEvent.type(screen.getByTestId(/searchByName/i), search1); - userEvent.click(searchBtn); - await wait(); - expect(screen.queryByText(/not found/i)).not.toBeInTheDocument(); - - const search2 = 'Pete{backspace}{backspace}{backspace}{backspace}'; - userEvent.type(screen.getByTestId(/searchByName/i), search2); - - const search3 = - 'John{backspace}{backspace}{backspace}{backspace}Sam{backspace}{backspace}{backspace}'; - userEvent.type(screen.getByTestId(/searchByName/i), search3); - - const search4 = 'Sam{backspace}{backspace}P{backspace}'; - userEvent.type(screen.getByTestId(/searchByName/i), search4); - - const search5 = 'Xe'; - userEvent.type(screen.getByTestId(/searchByName/i), search5); - userEvent.clear(screen.getByTestId(/searchByName/i)); - userEvent.type(screen.getByTestId(/searchByName/i), ''); - userEvent.click(searchBtn); - await wait(); - }); - - test('testing search not found', async () => { - await act(async () => { - render( - - - - - - - - - , - ); - }); - await wait(); - - 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(); - }); - - test('Testing User data is not present', async () => { - render( - - - - - - - - - , - ); - - await wait(); - expect(screen.getByText(/No User Found/i)).toBeTruthy(); - }); - - test('Should render warning alert when there are no organizations', async () => { - const { container } = render( - - - - - - - - - - , - ); - - await wait(200); - expect(container.textContent).toMatch( - 'Organizations not found, please create an organization through dashboard', - ); - }); - - test('Should not render warning alert when there are organizations present', async () => { - const { container } = render( - - - - - - - - - - , - ); - - await wait(); - - expect(container.textContent).not.toMatch( - 'Organizations not found, please create an organization through dashboard', - ); - }); - - test('Testing filter functionality', async () => { - await act(async () => { - render( - - - - - - - - - - , - ); - }); - await wait(); - - const searchInput = screen.getByTestId('filter'); - expect(searchInput).toBeInTheDocument(); - - const inputText = screen.getByTestId('filterUsers'); - - await act(async () => { - fireEvent.click(inputText); - }); - - const toggleText = screen.getByTestId('admin'); - - await act(async () => { - fireEvent.click(toggleText); - }); - - expect(searchInput).toBeInTheDocument(); - - await act(async () => { - fireEvent.click(inputText); - }); - - let toggleTite = screen.getByTestId('superAdmin'); - - await act(async () => { - fireEvent.click(toggleTite); - }); - - expect(searchInput).toBeInTheDocument(); - - await act(async () => { - fireEvent.click(inputText); - }); - - toggleTite = screen.getByTestId('user'); - - await act(async () => { - fireEvent.click(toggleTite); - }); - - expect(searchInput).toBeInTheDocument(); - - await act(async () => { - fireEvent.click(inputText); - }); - - toggleTite = screen.getByTestId('cancel'); - - await act(async () => { - fireEvent.click(toggleTite); - }); - - await wait(); - - expect(searchInput).toBeInTheDocument(); - }); - - test('check for rerendering', async () => { - const { rerender } = render( - - - - - - - - - - , - ); - - await wait(); - rerender( - - - - - - - - - - , - ); - await wait(); - }); - - test('should set hasMore to false if users length is less than perPageResult', async () => { - const link = new StaticMockLink(EMPTY_MOCKS, true); - - render( - - - - - - - - - - , - ); - - await wait(200); - - // Check if "No User Found" is displayed - expect(screen.getByText(/No User Found/i)).toBeInTheDocument(); - }); - - test('should filter users correctly', async () => { - await act(async () => { - render( - - - - - - - - - - , - ); - }); - await wait(); - - const filterButton = screen.getByTestId('filterUsers'); - - await act(async () => { - fireEvent.click(filterButton); - }); - - const filterAdmin = screen.getByTestId('admin'); - - await act(async () => { - fireEvent.click(filterAdmin); - }); - - await wait(); - expect(screen.getByText('Jane Doe')).toBeInTheDocument(); - - await act(async () => { - fireEvent.click(filterButton); - }); - - const filterSuperAdmin = screen.getByTestId('superAdmin'); - - await act(async () => { - fireEvent.click(filterSuperAdmin); - }); - - await wait(); - expect(screen.getByText('John Doe')).toBeInTheDocument(); - - await act(async () => { - fireEvent.click(filterButton); - }); - - const filterUser = screen.getByTestId('user'); - await act(async () => { - fireEvent.click(filterUser); - }); - - await wait(); - expect(screen.getByText('Jack Smith')).toBeInTheDocument(); - - await act(async () => { - fireEvent.click(filterButton); - }); - - 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(); - }); - - test('Users should be sorted and filtered correctly', async () => { - await act(async () => { - render( - - - - - - - - - - , - ); - }); - await wait(); - - // Check if the sorting and filtering logic was applied correctly - const rows = screen.getAllByRole('row'); - - const firstRow = rows[1]; - const secondRow = rows[2]; - - expect(firstRow).toHaveTextContent('John Doe'); - expect(secondRow).toHaveTextContent('Jane Doe'); - - await wait(); - - const inputText = screen.getByTestId('sortUsers'); - - await act(async () => { - fireEvent.click(inputText); - }); - - const toggleText = screen.getByTestId('oldest'); - - await act(async () => { - fireEvent.click(toggleText); - fireEvent.click(inputText); - }); - - const toggleTite = screen.getByTestId('newest'); - - await act(async () => { - fireEvent.click(toggleTite); - }); - - // 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 - - await wait(); - - await act(async () => { - fireEvent.click(inputText); - }); - - const toggleOld = screen.getByTestId('oldest'); - - await act(async () => { - fireEvent.click(toggleOld); - fireEvent.click(inputText); - }); - - 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 72acba5b5c..936807f1ec 100644 --- a/src/screens/Users/Users.tsx +++ b/src/screens/Users/Users.tsx @@ -16,7 +16,7 @@ import TableLoader from 'components/TableLoader/TableLoader'; import UsersTableItem from 'components/UsersTableItem/UsersTableItem'; import InfiniteScroll from 'react-infinite-scroll-component'; import type { InterfaceQueryUserListItem } from 'utils/interfaces'; -import styles from './Users.module.css'; +import styles from '../../style/app.module.css'; import useLocalStorage from 'utils/useLocalstorage'; import type { ApolloError } from '@apollo/client'; /** @@ -70,29 +70,42 @@ const Users = (): JSX.Element => { const { getItem } = useLocalStorage(); const perPageResult = 12; + const tableLoaderRowLength = 4; const [isLoading, setIsLoading] = useState(true); const [hasMore, setHasMore] = useState(true); const [isLoadingMore, setIsLoadingMore] = useState(false); const [searchByName, setSearchByName] = useState(''); const [sortingOption, setSortingOption] = useState('newest'); const [filteringOption, setFilteringOption] = useState('cancel'); + const [loadUnqUsers, setLoadUnqUsers] = useState(0); const userType = getItem('SuperAdmin') ? 'SUPERADMIN' : getItem('AdminFor') ? 'ADMIN' : 'USER'; const loggedInUserId = getItem('id'); + const [usersData, setUsersData] = useState< + { users: InterfaceQueryUserListItem[] } | undefined + >(undefined); const { - data: usersData, + data, loading: loading, fetchMore, refetch: refetchUsers, }: { data?: { users: InterfaceQueryUserListItem[] }; loading: boolean; - fetchMore: any; - refetch: any; + fetchMore: (options: { + variables: Record; + updateQuery: ( + previousQueryResult: { users: InterfaceQueryUserListItem[] }, + options: { + fetchMoreResult?: { users: InterfaceQueryUserListItem[] }; + }, + ) => { users: InterfaceQueryUserListItem[] }; + }) => void; + refetch: (variables?: Record) => void; error?: ApolloError; } = useQuery(USER_LIST, { variables: { @@ -105,6 +118,12 @@ const Users = (): JSX.Element => { notifyOnNetworkStatusChange: true, }); + useEffect(() => { + if (data) { + setUsersData(data); + } + }, [data, isLoading]); + const { data: dataOrgs } = useQuery(ORGANIZATION_CONNECTION_LIST); const [displayedUsers, setDisplayedUsers] = useState(usersData?.users || []); @@ -113,14 +132,13 @@ const Users = (): JSX.Element => { if (!usersData) { return; } + if (usersData.users.length < perPageResult) { setHasMore(false); } - if (usersData && usersData.users) { - let newDisplayedUsers = sortUsers(usersData.users, sortingOption); - newDisplayedUsers = filterUsers(newDisplayedUsers, filteringOption); - setDisplayedUsers(newDisplayedUsers); - } + let newDisplayedUsers = sortUsers(usersData.users, sortingOption); + newDisplayedUsers = filterUsers(newDisplayedUsers, filteringOption); + setDisplayedUsers(newDisplayedUsers); }, [usersData, sortingOption, filteringOption]); // To clear the search when the component is unmounted @@ -157,6 +175,12 @@ const Users = (): JSX.Element => { } }, [loading]); + useEffect(() => { + if (loadUnqUsers > 0) { + loadMoreUsers(displayedUsers.length, loadUnqUsers); + } + }, [displayedUsers]); + const handleSearch = (value: string): void => { setSearchByName(value); if (value === '') { @@ -171,9 +195,11 @@ const Users = (): JSX.Element => { setHasMore(true); }; - const handleSearchByEnter = (e: any): void => { + const handleSearchByEnter = ( + e: React.KeyboardEvent, + ): void => { if (e.key === 'Enter') { - const { value } = e.target; + const { value } = e.target as HTMLInputElement; handleSearch(value); } }; @@ -197,12 +223,12 @@ const Users = (): JSX.Element => { setHasMore(true); }; /* istanbul ignore next */ - const loadMoreUsers = (): void => { + const loadMoreUsers = (skipValue: number, limitVal: number): void => { setIsLoadingMore(true); fetchMore({ variables: { - skip: usersData?.users.length || 0, - userType: 'ADMIN', + first: limitVal + perPageResult || perPageResult, + skip: skipValue - perPageResult >= 0 ? skipValue - perPageResult : 0, filter: searchByName, order: sortingOption === 'newest' ? 'createdAt_DESC' : 'createdAt_ASC', }, @@ -211,23 +237,37 @@ const Users = (): JSX.Element => { { fetchMoreResult, }: { - fetchMoreResult: { users: InterfaceQueryUserListItem[] } | undefined; + fetchMoreResult?: { users: InterfaceQueryUserListItem[] }; }, - ): { users: InterfaceQueryUserListItem[] } | undefined => { + ) => { setIsLoadingMore(false); - if (!fetchMoreResult) return prev; - if (fetchMoreResult.users.length < perPageResult) { - setHasMore(false); + if (!fetchMoreResult) return prev || { users: [] }; + + const mergedUsers = [...(prev?.users || []), ...fetchMoreResult.users]; + + const uniqueUsers = Array.from( + new Map(mergedUsers.map((user) => [user.user._id, user])).values(), + ); + if (uniqueUsers.length < mergedUsers.length) { + setLoadUnqUsers(mergedUsers.length - uniqueUsers.length); + } else setLoadUnqUsers(0); + + // Load more users will always run after the initial request, hence prev is not going to be undefined + if (prev?.users) { + if (uniqueUsers.length - prev?.users.length < perPageResult) { + setHasMore(false); + } } - return { - users: [...(prev?.users || []), ...(fetchMoreResult.users || [])], - }; + + return { users: uniqueUsers }; }, }); }; const handleSorting = (option: string): void => { - setDisplayedUsers([]); + if (option === sortingOption) { + return; + } setHasMore(true); setSortingOption(option); }; @@ -245,19 +285,21 @@ const Users = (): JSX.Element => { new Date(a.user.createdAt).getTime(), ); return sortedUsers; - } else { - sortedUsers.sort( - (a, b) => - new Date(a.user.createdAt).getTime() - - new Date(b.user.createdAt).getTime(), - ); - return sortedUsers; } + sortedUsers.sort( + (a, b) => + new Date(a.user.createdAt).getTime() - + new Date(b.user.createdAt).getTime(), + ); + return sortedUsers; }; const handleFiltering = (option: string): void => { - setDisplayedUsers([]); + if (option === filteringOption) { + return; + } setFilteringOption(option); + setHasMore(true); }; const filterUsers = ( @@ -341,13 +383,17 @@ const Users = (): JSX.Element => { handleSorting('newest')} + onClick={(): void => { + handleSorting('newest'); + }} data-testid="newest" > {t('Newest')} handleSorting('oldest')} + onClick={(): void => { + handleSorting('oldest'); + }} data-testid="oldest" > {t('Oldest')} @@ -401,80 +447,89 @@ const Users = (): JSX.Element => { usersData && displayedUsers.length === 0 && searchByName.length > 0 ? ( -
+

{tCommon('noResultsFoundFor')} "{searchByName}"

-
+ ) : isLoading == false && usersData === undefined && displayedUsers.length === 0 ? ( -
+

{t('noUserFound')}

) : (
- {isLoading ? ( - - ) : ( - - } - hasMore={hasMore} - className={styles.listBox} - data-testid="users-list" - endMessage={ -
-
{tCommon('endOfResults')}
-
- } - > - - - - {headerTitles.map((title: string, index: number) => { + {isLoading && ( + + )} + { + loadMoreUsers(displayedUsers.length, perPageResult); + }} + loader={ + + } + hasMore={hasMore} + className={styles.listBox} + data-testid="users-list" + endMessage={ +
+
{tCommon('endOfResults')}
+
+ } + > +
+ + + {headerTitles.map((title: string, index: number) => { + return ( + + ); + })} + + + + {usersData && + displayedUsers.map( + (user: InterfaceQueryUserListItem, index: number) => { return ( - + ); - })} - - - - {usersData && - displayedUsers.map( - (user: InterfaceQueryUserListItem, index: number) => { - return ( - - ); - }, - )} - -
+ {title} +
- {title} -
-
- )} + }, + )} + + +
)} ); }; - export default Users; diff --git a/src/screens/Users/UsersMocks.ts b/src/screens/Users/UsersMocks.ts index ff346a1c97..f7908cf675 100644 --- a/src/screens/Users/UsersMocks.ts +++ b/src/screens/Users/UsersMocks.ts @@ -478,7 +478,6 @@ export const EMPTY_MOCKS = [ { request: { query: USER_LIST, - variables: { first: 12, skip: 0, diff --git a/src/setup/askForCustomPort/askForCustomPort.spec.ts b/src/setup/askForCustomPort/askForCustomPort.spec.ts new file mode 100644 index 0000000000..08e67cec00 --- /dev/null +++ b/src/setup/askForCustomPort/askForCustomPort.spec.ts @@ -0,0 +1,106 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import inquirer from 'inquirer'; +import { askForCustomPort, validatePort } from './askForCustomPort'; + +vi.mock('inquirer'); + +describe('askForCustomPort', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + describe('basic port validation', () => { + it('should return default port if user provides no input', async () => { + vi.spyOn(inquirer, 'prompt').mockResolvedValueOnce({ + customPort: '4321', + }); + + const result = await askForCustomPort(); + expect(result).toBe(4321); + }); + + it('should return user-provided port', async () => { + vi.spyOn(inquirer, 'prompt').mockResolvedValueOnce({ + customPort: '8080', + }); + + const result = await askForCustomPort(); + expect(result).toBe(8080); + }); + + it('should return validation error if port not between 1 and 65535', () => { + expect(validatePort('abcd')).toBe( + 'Please enter a valid port number between 1 and 65535.', + ); + expect(validatePort('-1')).toBe( + 'Please enter a valid port number between 1 and 65535.', + ); + expect(validatePort('70000')).toBe( + 'Please enter a valid port number between 1 and 65535.', + ); + }); + }); + + describe('retry mechanism', () => { + it('should handle invalid port input and prompt again', async () => { + vi.spyOn(inquirer, 'prompt') + .mockResolvedValueOnce({ customPort: 'abcd' }) + .mockResolvedValueOnce({ customPort: '8080' }); + + const result = await askForCustomPort(); + expect(result).toBe(8080); + }); + + it('should return default port after maximum retry attempts', async () => { + vi.spyOn(inquirer, 'prompt') + .mockResolvedValueOnce({ customPort: 'invalid-port-attempt1' }) + .mockResolvedValueOnce({ customPort: 'invalid-port-attempt2' }) + .mockResolvedValueOnce({ customPort: 'invalid-port-attempt3' }) + .mockResolvedValueOnce({ customPort: 'invalid-port-attempt4' }) + .mockResolvedValueOnce({ customPort: 'invalid-port-attempt5' }) + .mockResolvedValueOnce({ customPort: 'invalid-port-attempt6' }); + + const result = await askForCustomPort(); + expect(result).toBe(4321); + }); + }); + + describe('reserved ports', () => { + it('should return user-provided port after confirming reserved port', async () => { + vi.spyOn(inquirer, 'prompt') + .mockResolvedValueOnce({ customPort: '80' }) + .mockResolvedValueOnce({ confirmPort: true }); + + const result = await askForCustomPort(); + expect(result).toBe(80); + }); + + it('should re-prompt user for port if reserved port confirmation is denied', async () => { + vi.spyOn(inquirer, 'prompt') + .mockResolvedValueOnce({ customPort: '80' }) + .mockResolvedValueOnce({ confirmPort: false }) + .mockResolvedValueOnce({ customPort: '8080' }); + + const result = await askForCustomPort(); + expect(result).toBe(8080); + }); + + it('should return default port if reserved port confirmation is denied after maximum retry attempts', async () => { + vi.spyOn(inquirer, 'prompt') + .mockResolvedValueOnce({ customPort: '80' }) + .mockResolvedValueOnce({ confirmPort: false }) + .mockResolvedValueOnce({ customPort: '80' }) + .mockResolvedValueOnce({ confirmPort: false }) + .mockResolvedValueOnce({ customPort: '80' }) + .mockResolvedValueOnce({ confirmPort: false }) + .mockResolvedValueOnce({ customPort: '80' }) + .mockResolvedValueOnce({ confirmPort: false }) + .mockResolvedValueOnce({ customPort: '80' }) + .mockResolvedValueOnce({ confirmPort: false }) + .mockResolvedValueOnce({ customPort: '80' }); + + const result = await askForCustomPort(); + expect(result).toBe(4321); + }); + }); +}); diff --git a/src/setup/askForCustomPort/askForCustomPort.test.ts b/src/setup/askForCustomPort/askForCustomPort.test.ts deleted file mode 100644 index 0df6259ba1..0000000000 --- a/src/setup/askForCustomPort/askForCustomPort.test.ts +++ /dev/null @@ -1,24 +0,0 @@ -import inquirer from 'inquirer'; -import { askForCustomPort } from './askForCustomPort'; - -jest.mock('inquirer'); - -describe('askForCustomPort', () => { - test('should return default port if user provides no input', async () => { - jest - .spyOn(inquirer, 'prompt') - .mockResolvedValueOnce({ customPort: '4321' }); - - const result = await askForCustomPort(); - expect(result).toBe('4321'); - }); - - test('should return user-provided port', async () => { - jest - .spyOn(inquirer, 'prompt') - .mockResolvedValueOnce({ customPort: '8080' }); - - const result = await askForCustomPort(); - expect(result).toBe('8080'); - }); -}); diff --git a/src/setup/askForCustomPort/askForCustomPort.ts b/src/setup/askForCustomPort/askForCustomPort.ts index 8a923f678f..dd0fd51854 100644 --- a/src/setup/askForCustomPort/askForCustomPort.ts +++ b/src/setup/askForCustomPort/askForCustomPort.ts @@ -1,14 +1,63 @@ import inquirer from 'inquirer'; -export async function askForCustomPort(): Promise { - const { customPort } = await inquirer.prompt([ +const DEFAULT_PORT = 4321; +const MAX_RETRY_ATTEMPTS = 5; + +export function validatePort(input: string): string | boolean { + const port = Number(input); + if ( + Number.isNaN(port) || + !Number.isInteger(port) || + port <= 0 || + port > 65535 + ) { + return 'Please enter a valid port number between 1 and 65535.'; + } + return true; +} + +export async function reservedPortWarning(port: number): Promise { + const { confirmPort } = await inquirer.prompt<{ confirmPort: boolean }>([ { - type: 'input', - name: 'customPort', - message: - 'Enter custom port for development server (leave blank for default 4321):', - default: 4321, + type: 'confirm', + name: 'confirmPort', + message: `Port ${port} is a reserved port. Are you sure you want to use it?`, + default: false, }, ]); - return customPort; + + return confirmPort; +} + +export async function askForCustomPort(): Promise { + let remainingAttempts = MAX_RETRY_ATTEMPTS; + + while (remainingAttempts--) { + const { customPort } = await inquirer.prompt<{ customPort: string }>([ + { + type: 'input', + name: 'customPort', + message: `Enter custom port for development server (leave blank for default ${DEFAULT_PORT}):`, + default: DEFAULT_PORT.toString(), + validate: validatePort, + }, + ]); + + if (customPort && validatePort(customPort) === true) { + if (Number(customPort) >= 1024) { + return Number(customPort); + } + + if ( + Number(customPort) < 1024 && + (await reservedPortWarning(Number(customPort))) + ) { + return Number(customPort); + } + } + } + console.log( + `\nMaximum attempts reached. Using default port ${DEFAULT_PORT}.`, + ); + return DEFAULT_PORT; } diff --git a/src/setup/askForTalawaApiUrl/askForTalawaApiUrl.test.ts b/src/setup/askForTalawaApiUrl/askForTalawaApiUrl.test.ts index b1490222b4..3a11a0d799 100644 --- a/src/setup/askForTalawaApiUrl/askForTalawaApiUrl.test.ts +++ b/src/setup/askForTalawaApiUrl/askForTalawaApiUrl.test.ts @@ -30,17 +30,9 @@ describe('askForTalawaApiUrl', () => { }); test('should return the default endpoint when the user does not enter anything', async () => { - const mockPrompt = jest - .spyOn(inquirer, 'prompt') - .mockImplementation(async (questions: any) => { - const answers: Record = {}; - questions.forEach( - (question: { name: string | number; default: any }) => { - answers[question.name] = question.default; - }, - ); - return answers; - }); + const mockPrompt = jest.spyOn(inquirer, 'prompt').mockResolvedValueOnce({ + endpoint: 'http://localhost:4000/graphql/', + }); const result = await askForTalawaApiUrl(); diff --git a/src/setup/askForTalawaApiUrl/askForTalawaApiUrl.ts b/src/setup/askForTalawaApiUrl/askForTalawaApiUrl.ts index 97daa1ac89..713ed7dc68 100644 --- a/src/setup/askForTalawaApiUrl/askForTalawaApiUrl.ts +++ b/src/setup/askForTalawaApiUrl/askForTalawaApiUrl.ts @@ -1,7 +1,7 @@ import inquirer from 'inquirer'; export async function askForTalawaApiUrl(): Promise { - const { endpoint } = await inquirer.prompt([ + const { endpoint } = await inquirer.prompt<{ endpoint: string }>([ { type: 'input', name: 'endpoint', diff --git a/src/setup/askForTalawaApiUrl/setupTalawaWebSocketUrl.spec.ts b/src/setup/askForTalawaApiUrl/setupTalawaWebSocketUrl.spec.ts new file mode 100644 index 0000000000..926444d8a6 --- /dev/null +++ b/src/setup/askForTalawaApiUrl/setupTalawaWebSocketUrl.spec.ts @@ -0,0 +1,43 @@ +import fs from 'fs'; +import { vi } from 'vitest'; +import inquirer from 'inquirer'; +import { askForTalawaApiUrl } from './askForTalawaApiUrl'; + +vi.mock('fs'); +vi.mock('inquirer', async () => { + const actual = await vi.importActual('inquirer'); + return { + ...actual, + prompt: vi.fn(), + }; +}); + +describe('WebSocket URL Configuration', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + test('should convert http URL to ws WebSocket URL', async () => { + const endpoint = 'http://example.com/graphql'; + const websocketUrl = endpoint.replace(/^http(s)?:\/\//, 'ws$1://'); + + expect(websocketUrl).toBe('ws://example.com/graphql'); + }); + + test('should convert https URL to wss WebSocket URL', async () => { + const endpoint = 'https://example.com/graphql'; + const websocketUrl = endpoint.replace(/^http(s)?:\/\//, 'ws$1://'); + + expect(websocketUrl).toBe('wss://example.com/graphql'); + }); + + test('should retain default WebSocket URL if no new endpoint is provided', async () => { + vi.spyOn(inquirer, 'prompt').mockResolvedValueOnce({ + endpoint: 'http://localhost:4000/graphql/', + }); + await askForTalawaApiUrl(); + + const writeFileSyncSpy = vi.spyOn(fs, 'writeFileSync'); + expect(writeFileSyncSpy).not.toHaveBeenCalled(); + }); +}); diff --git a/src/setup/checkConnection/checkConnection.test.ts b/src/setup/checkConnection/checkConnection.spec.ts similarity index 84% rename from src/setup/checkConnection/checkConnection.test.ts rename to src/setup/checkConnection/checkConnection.spec.ts index c6f5251bdf..724f1a49dd 100644 --- a/src/setup/checkConnection/checkConnection.test.ts +++ b/src/setup/checkConnection/checkConnection.spec.ts @@ -1,8 +1,8 @@ import { checkConnection } from './checkConnection'; +import { vi, describe, beforeEach, it, expect } from 'vitest'; +vi.mock('node-fetch'); -jest.mock('node-fetch'); - -global.fetch = jest.fn((url) => { +global.fetch = vi.fn((url) => { if (url === 'http://example.com/graphql/') { const responseInit: ResponseInit = { status: 200, @@ -22,11 +22,11 @@ global.fetch = jest.fn((url) => { describe('checkConnection', () => { beforeEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); }); test('should return true and log success message if the connection is successful', async () => { - jest.spyOn(console, 'log').mockImplementation((string) => string); + vi.spyOn(console, 'log').mockImplementation((string) => string); const result = await checkConnection('http://example.com/graphql/'); expect(result).toBe(true); @@ -39,7 +39,7 @@ describe('checkConnection', () => { }); it('should return false and log error message if the connection fails', async () => { - jest.spyOn(console, 'log').mockImplementation((string) => string); + vi.spyOn(console, 'log').mockImplementation((string) => string); const result = await checkConnection( 'http://example_not_working.com/graphql/', ); diff --git a/src/setup/checkEnvFile/checkEnvFile.test.ts b/src/setup/checkEnvFile/checkEnvFile.spec.ts similarity index 62% rename from src/setup/checkEnvFile/checkEnvFile.test.ts rename to src/setup/checkEnvFile/checkEnvFile.spec.ts index a23976db4a..c2b75db0a6 100644 --- a/src/setup/checkEnvFile/checkEnvFile.test.ts +++ b/src/setup/checkEnvFile/checkEnvFile.spec.ts @@ -1,11 +1,22 @@ import fs from 'fs'; import { checkEnvFile } from './checkEnvFile'; +import { vi } from 'vitest'; -jest.mock('fs'); +/** + * This file contains unit tests for the `checkEnvFile` function. + * + * The tests cover: + * - Behavior when the `.env` file is missing required keys and appending them appropriately. + * - Ensuring no changes are made when all keys are present in the `.env` file. + * + * These tests utilize Vitest for test execution and mock the `fs` module to simulate file operations. + */ + +vi.mock('fs'); describe('checkEnvFile', () => { beforeEach(() => { - jest.resetAllMocks(); + vi.resetAllMocks(); }); it('should append missing keys to the .env file', () => { @@ -13,13 +24,12 @@ describe('checkEnvFile', () => { const envExampleContent = 'EXISTING_KEY=existing_value\nNEW_KEY=default_value\n'; - jest - .spyOn(fs, 'readFileSync') + vi.spyOn(fs, 'readFileSync') .mockReturnValueOnce(envContent) .mockReturnValueOnce(envExampleContent) .mockReturnValueOnce(envExampleContent); - jest.spyOn(fs, 'appendFileSync'); + vi.spyOn(fs, 'appendFileSync'); checkEnvFile(); @@ -33,12 +43,11 @@ describe('checkEnvFile', () => { const envContent = 'EXISTING_KEY=existing_value\n'; const envExampleContent = 'EXISTING_KEY=existing_value\n'; - jest - .spyOn(fs, 'readFileSync') + vi.spyOn(fs, 'readFileSync') .mockReturnValueOnce(envContent) .mockReturnValueOnce(envExampleContent); - jest.spyOn(fs, 'appendFileSync'); + vi.spyOn(fs, 'appendFileSync'); checkEnvFile(); diff --git a/src/setupTests.ts b/src/setupTests.ts index eac7093309..d204b3ddc9 100644 --- a/src/setupTests.ts +++ b/src/setupTests.ts @@ -32,4 +32,4 @@ jestPreviewConfigure({ autoPreview: true, }); -jest.setTimeout(15000); +jest.setTimeout(18000); diff --git a/src/state/action-creators/index.test.ts b/src/state/action-creators/index.spec.ts similarity index 90% rename from src/state/action-creators/index.test.ts rename to src/state/action-creators/index.spec.ts index 33aa642b8a..141eb679d9 100644 --- a/src/state/action-creators/index.test.ts +++ b/src/state/action-creators/index.spec.ts @@ -1,3 +1,4 @@ +import { vi } from 'vitest'; import { updateInstalled, installPlugin, @@ -10,7 +11,7 @@ describe('Testing rc/state/action-creators/index.ts', () => { const temp = updateInstalled('testPlug'); expect(typeof temp).toBe('function'); //stubbing the childfunction to check execution - const childFunction = jest.fn(); + const childFunction = vi.fn(); temp(childFunction); expect(childFunction).toHaveBeenCalled(); }); @@ -20,7 +21,7 @@ describe('Testing rc/state/action-creators/index.ts', () => { const temp = installPlugin('testPlug'); expect(typeof temp).toBe('function'); //stubbing the childfunction to check execution - const childFunction = jest.fn(); + const childFunction = vi.fn(); temp(childFunction); expect(childFunction).toHaveBeenCalled(); }); @@ -30,7 +31,7 @@ describe('Testing rc/state/action-creators/index.ts', () => { const temp = removePlugin('testPlug'); expect(typeof temp).toBe('function'); //stubbing the childfunction to check execution - const childFunction = jest.fn(); + const childFunction = vi.fn(); temp(childFunction); expect(childFunction).toHaveBeenCalled(); }); @@ -40,7 +41,7 @@ describe('Testing rc/state/action-creators/index.ts', () => { const temp = updatePluginLinks('testPlug'); expect(typeof temp).toBe('function'); //stubbing the childfunction to check execution - const childFunction = jest.fn(); + const childFunction = vi.fn(); temp(childFunction); expect(childFunction).toHaveBeenCalled(); }); diff --git a/src/state/helpers/Action.test.ts b/src/state/helpers/Action.spec.ts similarity index 53% rename from src/state/helpers/Action.test.ts rename to src/state/helpers/Action.spec.ts index a971c6c160..cc81153617 100644 --- a/src/state/helpers/Action.test.ts +++ b/src/state/helpers/Action.spec.ts @@ -1,8 +1,11 @@ import type { InterfaceAction } from './Action'; test('Testing Reducer Action Interface', () => { - ({ + const action = { type: 'STRING_ACTION_TYPE', payload: 'ANY_PAYLOAD', - }) as InterfaceAction; + } as InterfaceAction; + + expect(action.type).toBe('STRING_ACTION_TYPE'); + expect(action.payload).toBe('ANY_PAYLOAD'); }); diff --git a/src/state/reducers/pluginReducer.test.ts b/src/state/reducers/pluginReducer.spec.ts similarity index 100% rename from src/state/reducers/pluginReducer.test.ts rename to src/state/reducers/pluginReducer.spec.ts diff --git a/src/state/reducers/routesReducer.test.ts b/src/state/reducers/routesReducer.spec.ts similarity index 100% rename from src/state/reducers/routesReducer.test.ts rename to src/state/reducers/routesReducer.spec.ts diff --git a/src/state/reducers/userRoutersReducer.test.ts b/src/state/reducers/userRoutersReducer.spec.ts similarity index 72% rename from src/state/reducers/userRoutersReducer.test.ts rename to src/state/reducers/userRoutersReducer.spec.ts index 98c4a78464..9eb5a5327f 100644 --- a/src/state/reducers/userRoutersReducer.test.ts +++ b/src/state/reducers/userRoutersReducer.spec.ts @@ -14,9 +14,12 @@ describe('Testing Routes reducer', () => { { name: 'Posts', url: 'user/organization/undefined' }, { name: 'People', url: 'user/people/undefined' }, { name: 'Events', url: 'user/events/undefined' }, + { name: 'Volunteer', url: 'user/volunteer/undefined' }, { name: 'Donate', url: 'user/donate/undefined' }, + { name: 'Chat', url: 'user/chat/undefined' }, { name: 'Campaigns', url: 'user/campaigns/undefined' }, { name: 'My Pledges', url: 'user/pledges/undefined' }, + { name: 'Leave Organization', url: 'user/leaveorg/undefined' }, ], components: [ { @@ -31,13 +34,24 @@ describe('Testing Routes reducer', () => { }, { name: 'People', comp_id: 'people', component: 'People' }, { name: 'Events', comp_id: 'events', component: 'Events' }, + { + name: 'Volunteer', + comp_id: 'volunteer', + component: 'VolunteerManagement', + }, { name: 'Donate', comp_id: 'donate', component: 'Donate' }, + { name: 'Chat', comp_id: 'chat', component: 'Chat' }, { name: 'Campaigns', comp_id: 'campaigns', component: 'Campaigns', }, { name: 'My Pledges', comp_id: 'pledges', component: 'Pledges' }, + { + name: 'Leave Organization', + comp_id: 'leaveorg', + component: 'LeaveOrganization', + }, ], }); }); @@ -54,9 +68,12 @@ describe('Testing Routes reducer', () => { { name: 'Posts', url: 'user/organization/orgId' }, { name: 'People', url: 'user/people/orgId' }, { name: 'Events', url: 'user/events/orgId' }, + { name: 'Volunteer', url: 'user/volunteer/orgId' }, { name: 'Donate', url: 'user/donate/orgId' }, + { name: 'Chat', url: 'user/chat/orgId' }, { name: 'Campaigns', url: 'user/campaigns/orgId' }, { name: 'My Pledges', url: 'user/pledges/orgId' }, + { name: 'Leave Organization', url: 'user/leaveorg/orgId' }, ], components: [ { @@ -71,13 +88,24 @@ describe('Testing Routes reducer', () => { }, { name: 'People', comp_id: 'people', component: 'People' }, { name: 'Events', comp_id: 'events', component: 'Events' }, + { + name: 'Volunteer', + comp_id: 'volunteer', + component: 'VolunteerManagement', + }, { name: 'Donate', comp_id: 'donate', component: 'Donate' }, + { name: 'Chat', comp_id: 'chat', component: 'Chat' }, { name: 'Campaigns', comp_id: 'campaigns', component: 'Campaigns', }, { name: 'My Pledges', comp_id: 'pledges', component: 'Pledges' }, + { + name: 'Leave Organization', + comp_id: 'leaveorg', + component: 'LeaveOrganization', + }, ], }); }); diff --git a/src/state/reducers/userRoutesReducer.ts b/src/state/reducers/userRoutesReducer.ts index 44bc91fabb..90498e4bf6 100644 --- a/src/state/reducers/userRoutesReducer.ts +++ b/src/state/reducers/userRoutesReducer.ts @@ -55,13 +55,20 @@ const components: ComponentType[] = [ }, { name: 'People', comp_id: 'people', component: 'People' }, { name: 'Events', comp_id: 'events', component: 'Events' }, + { name: 'Volunteer', comp_id: 'volunteer', component: 'VolunteerManagement' }, { name: 'Donate', comp_id: 'donate', component: 'Donate' }, + { name: 'Chat', comp_id: 'chat', component: 'Chat' }, { name: 'Campaigns', comp_id: 'campaigns', component: 'Campaigns', }, { name: 'My Pledges', comp_id: 'pledges', component: 'Pledges' }, + { + name: 'Leave Organization', + comp_id: 'leaveorg', + component: 'LeaveOrganization', + }, ]; const generateRoutes = ( diff --git a/src/state/store.test.tsx b/src/state/store.spec.tsx similarity index 100% rename from src/state/store.test.tsx rename to src/state/store.spec.tsx diff --git a/src/style/app.module.css b/src/style/app.module.css new file mode 100644 index 0000000000..9480b80d20 --- /dev/null +++ b/src/style/app.module.css @@ -0,0 +1,3483 @@ +:root { + --brown-color: #555555; + --dropdown-hover-color: #eff1f7; + --grey-bg-color: #eaebef; + --grey-border-box-color: #e8e5e5; + --subtle-blue-grey: #7c9beb; + --subtle-blue-grey-hover: #5f7e91; + --modal-width: 670px; + --modal-max-width: 680px; + --input-shadow-color: #dddddd; + --delete-button-bg: #f8d6dc; + --delete-button-color: #ff4d4f; + --search-button-bg: #a8c7fa; + --search-button-border: #555555; + --table-image-size: 50px; + --table-image-small-size: 25px; + --bs-primary: #0056b3; + --bs-white: #fff; + --table-head-bg: var( + --bs-primary, + blue + ); /* Assuming var(--bs-primary) is defined elsewhere */ + --loader-size: 10em; + --loader-border-width: 1.1em; + --loader-color: #febc59; + --table-head-color: white; + --table-header-color: var(--bs-greyish-black, black); + --table-head-radius: 20px; + --table-bg-color: #eaebef; + --tablerow-bg-color: #eff1f7; + --row-background: var(--bs-white, white); + --font-size-header: 16px; +} +.fonts { + color: #707070; +} + +.fonts > span { + font-weight: 600; +} + +.cards > h2 { + font-size: 19px; +} +.cards > h3 { + font-size: 17px; +} +.cards > p { + font-size: 14px; + margin-top: -5px; + margin-bottom: 7px; +} + +.cards:hover { + filter: brightness(0.8); +} +.cards:hover::before { + opacity: 0.5; +} + +.cards:hover::after { + opacity: 1; + mix-blend-mode: normal; +} + +.cards:last-child:nth-last-child(odd) { + grid-column: auto / span 2; +} + +.cards:first-child:nth-last-child(even), +.cards:first-child:nth-last-child(even) ~ .box { + grid-column: auto / span 1; +} + +.capacityLabel { + background-color: var(--bs-primary); + color: white; + height: 22.19px; + font-size: 12px; + font-weight: bolder; + padding: 0.1rem 0.3rem; + border-radius: 0.5rem; + position: relative; + overflow: hidden; +} + +.capacityLabel svg { + margin-bottom: 3px; +} + +.sidebar { + z-index: 0; + padding-top: 5px; + margin: 0; + height: 100%; +} +.sidebar:after { + background-color: #f7f7f7; + position: absolute; + width: 2px; + height: 600px; + top: 10px; + left: 94%; + display: block; +} +.sidebarsticky { + padding-left: 45px; + margin-top: 7px; +} +.sidebarsticky > p { + margin-top: -10px; +} + +.logintitle { + color: #707070; + font-weight: 600; + font-size: 20px; + margin-bottom: 30px; + padding-bottom: 5px; + border-bottom: 3px solid #31bb6b; + width: 15%; +} + +.searchtitle { + color: #707070; + font-weight: 600; + font-size: 18px; + margin-bottom: 20px; + padding-bottom: 5px; + border-bottom: 3px solid #31bb6b; + width: 60%; +} + +.admindetails { + display: flex; + justify-content: space-between; +} + +.admindetails > p { + margin-top: -12px; + margin-right: 30px; +} + +.mainpageright > hr { + margin-top: 20px; + width: 100%; + margin-left: -15px; + margin-right: -15px; + margin-bottom: 20px; +} + +.justifysp { + display: flex; + justify-content: space-between; +} + +@media screen and (max-width: 575.5px) { + .justifysp { + padding-left: 55px; + display: flex; + justify-content: space-between; + width: 100%; + } +} + +.sidebarsticky > input { + text-decoration: none; + margin-bottom: 50px; + border-color: var(--grey-border-box-color); + width: 80%; + border-radius: 7px; + padding-top: 5px; + padding-bottom: 5px; + padding-right: 10px; + padding-left: 10px; + box-shadow: none; +} + +.noOutline:is(:hover, :focus, :active, :focus-visible, .show) { + outline: none !important; +} + +.closeButton { + margin-bottom: 10px; + color: var(--delete-button-color); + margin-right: 5px; + background-color: var(--delete-button-bg); + border: var(--bs-white); +} + +.closeButton:hover { + color: var(--delete-button-bg) !important; + background-color: var(--delete-button-color) !important; + border: var(--bs-white); +} + +.modalContent { + width: var(--modal-width); + max-width: var(--modal-max-width); +} + +.subtleBlueGrey { + color: var(--subtle-blue-grey); + text-decoration: none; +} + +.subtleBlueGrey:hover { + color: var(--subtle-blue-grey-hover); + text-decoration: underline; +} + +.dropdown { + background-color: var(--bs-white); + border: 1px solid var(--brown-color); + color: var(--brown-color); + position: relative; + display: inline-block; + margin-top: 10px; + margin-bottom: 10px; +} + +.dropdown:is(:hover, :focus, :active, :focus-visible, .show) { + background-color: transparent !important; + border: 1px solid var(--brown-color); + color: var(--brown-color) !important; +} + +.dropdown:is(:focus, :focus-visible) { + outline: 2px solid var(--highlight-color, #a8c7fa); +} + +.dropdownItem { + background-color: var(--bs-white) !important; + color: var(--brown-color) !important; + border: none !important; +} + +.dropdownItem:focus, +.dropdownItem:hover { + outline: 2px solid var(--highlight-color, #a8c7fa); +} + +.dropdownItem:hover, +.dropdownItem:focus, +.dropdownItem:active { + background-color: var(--dropdown-hover-color, #e0e0e0) !important; + color: var(--brown-color) !important; + outline: none !important; + box-shadow: 0 0 4px var(--highlight-color, #a8c7fa); +} + +.input { + flex: 1; + position: relative; +} + +.btnsContainer { + display: flex; + margin: 2.5rem 0; + align-items: center; + gap: 10px; +} + +.btnsContainer .btnsBlock { + display: flex; + width: max-content; +} + +.btnsContainerBlockAndUnblock { + display: flex; + margin: 2.5rem 0 2.5rem 0; +} + +.btnsContainerBlockAndUnblock .btnsBlockBlockAndUnblock { + display: flex; +} + +.btnsContainerBlockAndUnblock .btnsBlockBlockAndUnblock button { + margin-left: 1rem; + display: flex; + justify-content: center; + align-items: center; +} + +.btnsContainerBlockAndUnblock .inputContainerBlockAndUnblock { + flex: 1; + position: relative; +} + +.btnsContainerBlockAndUnblock .inputBlockAndUnblock { + width: 70%; + position: relative; +} + +.btnsContainerBlockAndUnblock input { + outline: 1px solid var(--bs-gray-400); +} + +.btnsContainer .input button { + width: 52px; +} + +.deleteButton { + background-color: var(--delete-button-bg); + color: var(--delete-button-color); + border: none; + padding: 5px 20px; + display: flex; + align-items: center; + margin-top: 20px; + margin-right: auto; + margin-left: auto; + gap: 8px; +} + +.actionItemDeleteButton { + background-color: var(--delete-button-bg); + color: var(--delete-button-color); + border: none; +} + +.createButton { + background-color: var(--grey-bg-color) !important; + color: black !important; + margin-top: 10px; + margin-left: 5px; + border: 1px solid var(--brown-color); +} + +.createButton:hover { + background-color: var(--grey-bg-color) !important; + color: black !important; + border: 1px solid var(--brown-color) !important; +} + +.visuallyHidden { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; +} + +.inputField { + margin-top: 10px; + margin-bottom: 10px; + background-color: var(--bs-white); + box-shadow: 0 1px 1px var(--input-shadow-color); +} + +.inputFieldModal { + margin-bottom: 10px; + background-color: var(--bs-white); + box-shadow: 0 1px 1px var(--input-shadow-color); +} + +.inputField > button { + padding-top: 10px; + padding-bottom: 10px; +} + +.searchButton { + margin-bottom: 10px; + background-color: var(--search-button-bg); + border-color: var(--search-button-border); + position: absolute; + z-index: 10; + bottom: 0; + right: 0; + display: flex; + justify-content: center; + align-items: center; +} + +.searchButton:hover { + background-color: var(--search-button-hover-bg, #286fe0); + border-color: var(--search-button-border); +} + +.searchButton:active { + transform: scale(0.95); +} + +.addButton { + margin-bottom: 10px; + background-color: var(--search-button-bg); + border-color: var(--grey-bg-color); +} + +.addButton:hover { + background-color: #286fe0; + border-color: var(--search-button-border); +} + +.yesButton { + background-color: var(--search-button-bg); + border-color: var(--search-button-border); +} + +.searchIcon { + color: var(--brown-color); +} + +.infoButton { + background-color: var(--search-button-bg); + border-color: var(--search-button-border); + color: var(--brown-color); + margin-right: 0.5rem; + border-radius: 0.25rem; +} + +.infoButton:hover { + background-color: #286fe0; + border-color: var(--search-button-border); +} + +.TableImage { + object-fit: cover; + /* margin-top: px !important; */ + margin-right: 5px; + width: var(--table-image-size) !important; + height: var(--table-image-size) !important; + border-radius: 100% !important; +} + +.tableHead { + color: var(--table-head-color); + border-radius: var(--table-head-radius) !important; + padding: 20px; + margin-top: 20px; +} + +.rowBackground { + background-color: var(--row-background); + max-height: 120px; + overflow-y: auto; +} + +.tableHeader { + background-color: var(--table-head-bg); + color: var(--table-header-color); + font-size: var(--font-size-header); +} + +.errorContainer { + min-height: 100vh; +} + +.errorIcon { + transform: scale(1.5); + color: var(--bs-danger); + margin-bottom: 1rem; + /* Add error icon for non-color indication */ + &::before { + content: '⚠️'; + margin-right: 0.5rem; + } +} + +.tag-template-name { + position: absolute; + left: 14.91px; + top: 27.03px; + width: 58.55px; + height: 5.67px; + text-align: center; + font-family: 'Roboto', sans-serif; + font-size: 16px; + letter-spacing: 0; + line-height: 1; + color: #08780b; +} + +.subTagsLink i { + visibility: hidden; +} + +.subTagsLink:hover, +.subTagsLink:focus { + color: var(--subtle-blue-grey-hover); + font-weight: 600; + text-decoration: underline; +} + +.subTagsLink:hover i, +.subTagsLink:focus i { + visibility: visible; +} + +.manageTagScrollableDiv { + scrollbar-width: thin; + scrollbar-color: var(--bs-gray-400) var(--bs-white); + max-height: calc(100vh - 18rem); + overflow: auto; +} + +.tagsBreadCrumbs:hover { + color: var(--bs-blue); + font-weight: 600; + text-decoration: underline; +} + +.orgUserTagsScrollableDiv { + scrollbar-width: auto; + scrollbar-color: var(--bs-gray-400) var(--bs-white); + + max-height: calc(100vh - 18rem); + overflow: auto; + position: sticky; +} + +input[type='checkbox']:checked + label { + background-color: var(--subtle-blue-grey) !important; +} + +input[type='radio']:checked + label:hover { + color: black !important; +} + +.actionItemsContainer { + height: 90vh; +} + +.actionItemModal { + max-width: 80vw; + margin-top: 2vh; + margin-left: 13vw; +} + +.datediv { + display: flex; + flex-direction: row; +} + +.datebox { + width: 90%; + border-radius: 7px; + outline: none; + box-shadow: none; + padding-top: 2px; + padding-bottom: 2px; + padding-right: 5px; + padding-left: 5px; + margin-right: 5px; + margin-left: 5px; +} + +hr { + border: none; + height: 1px; + background-color: var(--bs-gray-500); + margin: 1rem; +} + +.iconContainer { + display: flex; + justify-content: flex-end; +} + +.icon { + margin: 1px; +} + +.message { + margin-top: 25%; + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; +} + +.preview { + display: flex; + flex-direction: row; + font-weight: 900; + font-size: 16px; + color: rgb(80, 80, 80); +} + +.rankings { + aspect-ratio: 1; + border-radius: 50%; + width: 50px; +} + +.toggleGroup { + width: 50%; + min-width: 20rem; + margin: 0.5rem 0rem; +} + +.toggleBtn { + padding: 0rem; + height: 2rem; + display: flex; + justify-content: center; + align-items: center; +} + +.pageNotFound { + position: relative; + bottom: 20px; +} + +.pageNotFound h3 { + font-family: 'Roboto', sans-serif; + font-weight: normal; + letter-spacing: 1px; +} + +.pageNotFound .brand span { + margin-top: 50px; + font-size: 40px; +} + +.pageNotFound .brand h3 { + font-weight: 300; + margin: 10px 0 0 0; +} + +.pageNotFound h1.head { + font-size: 250px; + font-weight: 900; + color: #31bb6b; + letter-spacing: 25px; + margin: 10px 0 0 0; +} + +.pageNotFound h1.head span { + position: relative; + display: inline-block; +} +.pageNotFound h1.head span:before, +.pageNotFound h1.head span:after { + position: absolute; + top: 50%; + width: 50%; + height: 1px; + background: #fff; + content: ''; +} +.pageNotFound h1.head span:before { + left: -55%; +} + +.pageNotFound h1.head span:after { + right: -55%; +} + +.pledgeContainer { + margin: 0.6rem 0; +} + +.container { + min-height: 100vh; +} + +.pledgeModal { + max-width: 80vw; + margin-top: 2vh; + margin-left: 13vw; +} + +.greenregbtnPledge { + margin-top: 15px; + border: 1px solid var(--bs-gray-300); + box-shadow: 0 2px 2px var(--grey-border-box-color); + 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; +} + +.btnsContainerPledge { + display: flex; + gap: 0.8rem; + margin: 2.2rem 0 0.8rem 0; +} + +.btnsContainerPledge .inputPledge { + flex: 1; + min-width: 18rem; + position: relative; +} + +.btnsContainerPledge input { + outline: 1px solid var(--bs-gray-400); +} + +.btnsContainerPledge .inputPledge button { + width: 52px; +} + +.inputFieldPledge { + background-color: var(--bs-white); + box-shadow: 0 1px 1px #31bb6b; +} + +.dropdownPledge { + background-color: var(--bs-white); + border: 1px solid var(--bs-primary); + position: relative; + display: inline-block; + color: var(--bs-primary); +} + +.rowBackgroundPledge { + background-color: var(--bs-white); + max-height: 120px; +} + +.TableImagePledge { + object-fit: cover; + width: calc(var(--table-image-size) / 2) !important; + height: calc(var(--table-image-size) / 2) !important; + border-radius: 100% !important; +} + +.imageContainerPledge { + display: flex; + align-items: center; + justify-content: center; +} + +.pledgerContainer { + display: flex; + align-items: center; + justify-content: center; + margin: 0.1rem 0.25rem; + gap: 0.25rem; + padding: 0.25rem 0.45rem; + border-radius: 0.35rem; + background-color: var(--bs-primary-rgb, 49, 187, 107, 0.2); + height: 2.2rem; + margin-top: 0.75rem; +} + +.noOutlinePledge 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: var(--bs-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; +} + +.toggleGroupPledge { + width: 50%; + min-width: 27.75rem; + margin: 0.5rem 0rem; +} + +.toggleBtnPledge { + padding: 0rem; + height: 30px; + display: flex; + justify-content: center; + align-items: center; +} + +.toggleBtnPledge:hover { + color: #31bb6b !important; +} + +.card { + width: fit-content; +} + +.cardHeader { + padding: 1.25rem 1rem 1rem 1rem; + border-bottom: 1px solid var(--bs-gray-200); + display: flex; + justify-content: space-between; + align-items: center; +} + +.cardHeader .cardTitle { + font-size: 1.5rem; +} + +.formLabel { + font-weight: normal; + padding-bottom: 0; + font-size: 1rem; + color: black; +} + +.cardBody { + min-height: 180px; +} + +.cardBody .textBox { + margin: 0 0 3rem 0; + color: var(--bs-secondary); +} + +.socialInput { + height: 2.5rem; +} + +.eventContainer { + display: flex; + align-items: start; +} + +.eventDetailsBox { + position: relative; + box-sizing: border-box; + background: #ffffff; + width: 66%; + padding: 0.3rem; + box-shadow: 0 3px 8px rgba(0, 0, 0, 0.1); + border-radius: 20px; + margin-bottom: 0; + margin-top: 20px; +} +.ctacards { + padding: 20px; + width: 100%; + display: flex; + background-color: #ffffff; + margin: 0 4px; + justify-content: space-between; + box-shadow: 0 3px 8px rgba(0, 0, 0, 0.1); + align-items: center; + border-radius: 20px; +} +.ctacards span { + color: rgb(181, 181, 181); + font-size: small; +} + +.time { + display: flex; + justify-content: space-between; + padding: 15px; + padding-bottom: 0px; + width: 33%; + + box-sizing: border-box; + background: #ffffff; + box-shadow: 0 3px 8px rgba(0, 0, 0, 0.1); + border-radius: 20px; + margin-bottom: 0; + margin-top: 20px; + margin-left: 10px; +} + +.startTime, +.endTime { + display: flex; + font-size: 20px; +} + +.to { + padding-right: 10px; +} + +.startDate, +.endDate { + color: #808080; + font-size: 14px; +} + +.titlename { + font-weight: 600; + font-size: 25px; + padding: 15px; + padding-bottom: 0px; + width: 50%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.description { + color: #737373; + font-weight: 300; + font-size: 14px; + word-wrap: break-word; + padding: 15px; + padding-bottom: 0px; +} + +.toporgloc { + font-size: 16px; + padding: 0.5rem; +} + +.toporgloc span { + color: #737373; +} + +.eventAgendaItemContainer h2 { + margin: 0.6rem 0; +} + +@media (max-width: 768px) { + .btnsContainer { + margin-bottom: 0; + display: flex; + flex-direction: column; + } + + .createAgendaItemButton { + position: absolute; + top: 1rem; + right: 2rem; + } +} + +.customcell { + background-color: #31bb6b !important; + color: var(--bs-white) !important; + font-size: medium !important; + font-weight: 500 !important; + padding-top: 10px !important; + padding-bottom: 10px !important; +} + +.eventsAttended, +.membername { + color: blue; +} +.actionBtn { + background-color: #ffffff !important; +} +.actionBtn:hover, +.actionBtn:focus, +.actionBtn:active { + color: #39a440 !important; +} + +.table-body > .table-row { + background-color: #fff !important; +} + +.table-body > .table-row:nth-child(2n) { + background: #afffe8 !important; +} + +.organizationFundCampaignContainer { + margin: 0.5rem 0; +} + +.rowBackgroundOrganizationFundCampaign { + background-color: var(--bs-white); + max-height: 120px; +} + +.campaignModal { + max-width: 80vw; + margin-top: 2vh; + margin-left: 13vw; +} + +.greenregbtnOrganizationFundCampaign { + margin: 1rem 0 0; + margin-top: 15px; + border: 1px solid var(--bs-gray-300); + box-shadow: 0 2px 2px var(--grey-border-box-color); + 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; + flex: 1; +} + +.goalButtonOrganizationFundCampaign { + border: 1px solid var(--grey-border-box-color) !important; + color: #707070 !important; + width: 75%; + padding: 10px; + border-radius: 8px; + display: block; + margin: auto; + box-shadow: 5px 5px 4px 0px rgba(49, 187, 107, 0.12); +} + +.redregbtn { + margin: 1rem 0 0; + margin-top: 15px; + border: 1px solid var(--grey-border-box-color); + box-shadow: 0 2px 2px var(--grey-border-box-color); + padding: 10px 10px; + border-radius: 5px; + width: 100%; + font-size: 16px; + color: var(--bs-white); + outline: none; + font-weight: 600; + cursor: pointer; + transition: + transform 0.2s, + box-shadow 0.2s; + width: 100%; + flex: 1; +} + +.campaignNameInfo { + font-size: medium; + cursor: pointer; +} +.campaignNameInfo:hover { + color: blue; + transform: translateY(-2px); +} + +.inputFieldOrganizationFundCampaign { + background-color: var(--bs-white); + box-shadow: 0 1px 1px var(--search-button-bg); +} + +.dropdownOrganizationFundCampaign { + background-color: var(--bs-white); + border: 1px solid var(--grey-border-box-color); + position: relative; + display: inline-block; + color: #707070; +} + +.btnsContainerOrganizationFundCampaign { + display: flex; + margin: 2rem 0 2rem 0; + gap: 0.8rem; +} + +.btnsContainerOrganizationFundCampaign .btnsBlockOrganizationFundCampaign { + display: flex; + gap: 0.8rem; +} + +.btnsContainerOrganizationFundCampaign + .btnsBlockOrganizationFundCampaign + div + button { + display: flex; + margin-left: 1rem; + justify-content: center; + align-items: center; +} + +.btnsContainerOrganizationFundCampaign .inputOrganizationFundCampaign { + flex: 1; + position: relative; +} + +.btnsContainerOrganizationFundCampaign input { + outline: 1px solid var(--bs-gray-400); +} + +.btnsContainerOrganizationFundCampaign .inputOrganizationFundCampaign button { + width: 52px; +} + +@media (max-width: 1020px) { + .btnsContainerOrganizationFundCampaign { + flex-direction: column; + margin: 1.5rem 0; + } + + .btnsContainerOrganizationFundCampaign .btnsBlockOrganizationFundCampaign { + margin: 1.5rem 0 0 0; + justify-content: space-between; + } + + .btnsContainerOrganizationFundCampaign + .btnsBlockOrganizationFundCampaign + div + button { + margin: 0; + } + + .createFundBtn { + margin-top: 0; + } +} + +@media screen and (max-width: 575.5px) { + .mainpageright { + width: 98%; + } +} + +/* For mobile devices */ + +@media (max-width: 520px) { + .btnsContainerOrganizationFundCampaign { + margin-bottom: 0; + } + + .btnsContainerOrganizationFundCampaign .btnsBlockOrganizationFundCampaign { + display: block; + margin-top: 1rem; + margin-right: 0; + } + + .btnsContainerOrganizationFundCampaign + .btnsBlockOrganizationFundCampaign + div + button { + margin-bottom: 1rem; + margin-right: 0; + width: 100%; + } +} + +@media (max-width: 1024px) { + .pageNotFound h1.head { + font-size: 200px; + letter-spacing: 25px; + } +} + +@media (max-width: 768px) { + .pageNotFound h1.head { + font-size: 150px; + letter-spacing: 25px; + } +} + +@media (max-width: 640px) { + .pageNotFound h1.head { + font-size: 150px; + letter-spacing: 0; + } +} + +@media (max-width: 480px) { + .pageNotFound .brand h3 { + font-size: 20px; + } + .pageNotFound h1.head { + font-size: 130px; + letter-spacing: 0; + } + .pageNotFound h1.head span:before, + .pageNotFound h1.head span:after { + width: 40%; + } + .pageNotFound h1.head span:before { + left: -45%; + } + .pageNotFound h1.head span:after { + right: -45%; + } + .pageNotFound p { + font-size: 18px; + } +} + +@media (max-width: 320px) { + .pageNotFound .brand h3 { + font-size: 16px; + } + .pageNotFound h1.head { + font-size: 100px; + letter-spacing: 0; + } + .pageNotFound h1.head span:before, + .pageNotFound h1.head span:after { + width: 25%; + } + .pageNotFound h1.head span:before { + left: -30%; + } + .pageNotFound h1.head span:after { + right: -30%; + } +} +@media (max-width: 520px) { + .btnsContainer { + margin-bottom: 0; + } + + .btn { + flex-direction: column; + justify-content: center; + } + .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%; + } +} + +@media (max-width: 1120px) { + .contract { + padding-left: calc(250px + 2rem + 1.5rem); + } + + .listBox .itemCard { + width: 100%; + } +} + +@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; + } +} + +@-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); + } +} +.btnsContainer .input { + flex: 1; + position: relative; + max-width: 60%; + justify-content: space-between; +} + +.btnsContainer input { + outline: 1px solid var(--bs-gray-400); +} + +.list_box { + height: auto; + overflow-y: auto; + width: 100%; +} + +.fundName { + font-weight: 600; + cursor: pointer; +} + +.modalHeader { + border: none; + padding-bottom: 0; +} + +.label { + color: var(--bs-emphasis-color); +} + +.fundModal { + max-width: 80vw; + margin-top: 2vh; + margin-left: 13vw; +} + +.btnsContainer .btnsBlock button { + margin-left: 1rem; + display: flex; + justify-content: center; + align-items: center; +} + +.errorMessage { + margin-top: 25%; + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; +} + +.tableHeaders { + background-color: var(--bs-primary-text-emphasis); + color: var(--bs-white); + font-size: 1rem; +} + +.rowBackgrounds { + background-color: var(--bs-white); + max-height: 120px; + overflow-y: auto; /* Handle content overflow */ +} + +.subTagsLink { + color: var(--bs-blue); + font-weight: 500; + cursor: pointer; + /* Prevent layout shift */ + &::after { + display: block; + content: attr(data-text); + font-weight: 600; + height: 0; + overflow: hidden; + visibility: hidden; + } +} + +.tagsBreadCrumbs { + color: var(--bs-gray); + cursor: pointer; + /* Prevent layout shift */ + &::after { + display: block; + content: attr(data-text); + font-weight: 600; + height: 0; + overflow: hidden; + visibility: hidden; + } +} + +.tagsBreadCrumbs:hover, +.tagsBreadCrumbs:focus { + color: var(--bs-blue); + font-weight: 600; + text-decoration: underline; +} + +.subTagsScrollableDiv { + scrollbar-width: auto; + scrollbar-color: var(--bs-gray-400) var(--bs-white); + max-height: calc(100vh - 18rem); + overflow: auto; +} + +#individualRadio, +#requestsRadio, +#groupsRadio, +.toggleBtn:hover { + color: var(--brand-primary) !important; +} + +.toggleBtn:hover { + color: #31bb6b !important; +} + +input[type='radio']:checked + label { + background-color: var(--brand-primary-light) !important; +} + +input[type='radio']:checked + label:hover { + color: black !important; +} + +.dropdownToggle { + margin-bottom: 0; + display: flex; +} + +.dropdownModalToggle { + width: 50%; +} + +.greenregbtn { + margin-top: 1rem; + 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; + width: 100%; +} + +.manageBtn { + margin: 1rem 0 0; + margin-top: 15px; + border: 1px solid var(--grey-border-box-color); + box-shadow: 0 2px 2px var(--grey-border-box-color); + padding: 10px 10px; + border-radius: 5px; + font-size: 16px; + color: var(--bs-white); + outline: none; + font-weight: 600; + cursor: pointer; + width: 45%; + transition: + transform 0.2s, + box-shadow 0.2s; +} + +.removeFilterIcon { + cursor: pointer; +} + +.searchForm { + display: inline; +} + +.view { + margin-left: 2%; + font-weight: 600; + font-size: 16px; + color: var(--bs-gray-600); +} + +/* header (search, filter, dropdown) */ +.btncon .btnsContainer { + display: flex; + margin: 0.5rem 0 1.5rem 0; +} + +.btncon .btnsContainer .input { + flex: 1; + min-width: 18rem; + position: relative; +} + +.btncon .btnsContainer input { + outline: 1px solid var(--bs-gray-400); +} + +.btncon .btnsContainer .input button { + width: 52px; +} + +.noOutline input { + outline: none; +} + +.noOutline input:disabled { + -webkit-text-fill-color: black !important; +} + +.noOutline textarea:disabled { + color: var(--bs-black) !important; + opacity: 1; +} + +.inputFields { + box-shadow: 0 1px 1px var(--brand-primary); +} + +.dropdowns { + background-color: var(--bs-white); + border: 1px solid #31bb6b; + position: relative; + display: inline-block; + color: #31bb6b; +} + +.chipIcon { + height: 0.9rem !important; +} + +.chip { + height: 1.5rem !important; +} + +.active { + background-color: var(--status-active-bg); +} + +.pending { + background-color: var(--status-pending-bg); + color: var(--status-pending-text); + border-color: var(--status-pending-border); +} + +/* Modals */ +.itemModal { + 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; +} + +.imageContainer { + display: flex; + align-items: center; + justify-content: center; + margin-right: 0.5rem; +} + +.TableImages { + object-fit: cover; + width: var(--image-width, 100%); + height: var(--image-height, auto); + border-radius: 0; + margin-right: var(--image-spacing, 8px); +} + +.avatarContainer { + width: 28px; + height: 26px; +} + +/* Modal Table (Groups & Assignments) */ +.modalTable { + max-height: 220px; + overflow-y: auto; +} + +/* * Refortoring css for OrgList */ + +.btnsContainerOrgList { + display: flex; + margin: 2.5rem 0 2.5rem 0; +} + +.btnsContainerOrgList .btnsBlockOrgList { + display: flex; +} + +.orgCreationBtn { + width: 100%; + border: None; +} + +.enableEverythingBtn { + width: 100%; + border: None; +} + +.pluginStoreBtn { + width: 100%; + background-color: var(--bs-white); + color: var(--brown-color); + border: 0.5px solid var(--brown-color); +} +.searchButtonOrgList { + position: absolute; + z-index: 10; + bottom: 0; + inset-inline-end: 0px; + height: 100%; + display: flex; + justify-content: center; + align-items: center; +} + +.pluginStoreBtn:hover, +.pluginStoreBtn:focus { + background-color: var(--dropdown-hover-color) !important; + color: var(--brown-color) !important; + border-color: var(--brown-color) !important; +} + +.flexContainer { + display: flex; + justify-content: center; + align-items: center; + width: 100%; +} + +.orText { + display: block; + position: absolute; + top: -0.2rem; + left: calc(50% - 2.6rem); + margin: 0 auto; + padding: 0.5rem 2rem; + z-index: 100; + background: var(--bs-white); + color: var(--bs-secondary); +} + +.sampleOrgSection { + display: grid; + grid-template-columns: repeat(1, 1fr); + row-gap: 1em; + width: 100%; +} + +.sampleOrgCreationBtn { + width: 100%; + background-color: transparent; + color: #707070; + border-color: #707070; + display: flex; + justify-content: center; + align-items: center; +} + +.sampleHover:hover { + border-color: grey; + color: grey; +} + +.sampleModalTitle { + background-color: var(--bs-primary); +} + +.btnsContainerOrgList .btnsBlockOrgList button { + margin-left: 1rem; + display: flex; + justify-content: center; + align-items: center; +} + +.btnsContainerOrgList .inputOrgList { + flex: 1; + position: relative; +} + +.btnsContainerOrgList input { + outline: 1px solid var(--bs-gray-400); +} + +.btnsContainerOrgList .inputOrgList button { + width: 52px; +} + +.listBoxOrgList { + display: flex; + flex-wrap: wrap; + overflow: unset !important; +} + +.listBoxOrgList .itemCardOrgList { + width: 50%; +} +.notFound { + flex: 1; + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; +} + +.mainpage { + display: flex; + flex-direction: row; +} + +.editIcon { + position: absolute; + top: 10px; + left: 20px; + cursor: pointer; +} + +.selectWrapper { + position: relative; +} + +.selectWithChevron { + appearance: none; + padding-right: 30px; +} + +.selectWrapper::after { + content: '\25BC'; + position: absolute; + top: 50%; + right: 10px; + transform: translateY(-50%); + pointer-events: none; +} + +.sidebarstickyMemberDetail { + padding: 0 2rem; + text-overflow: ellipsis; + /* overflow-x: hidden; */ +} + +.sidebarstickyMemberDetail > p { + margin-top: -10px; +} + +.navitem { + padding-left: 27%; + padding-top: 12px; + padding-bottom: 12px; + cursor: pointer; +} + +.searchtitleMemberDetail { + color: #707070; + font-weight: 600; + font-size: 18px; + margin-top: 60px; + margin-bottom: 20px; + padding-bottom: 5px; + border-bottom: 3px solid #eaebef; + width: 60%; +} + +.contact { + width: 100%; +} + +.sidebarstickyMemberDetail > input { + text-decoration: none; + margin-bottom: 50px; + border-color: var(--grey-border-box-color); + width: 80%; + border-radius: 7px; + padding-top: 5px; + padding-bottom: 5px; + padding-right: 10px; + padding-left: 10px; + box-shadow: none; +} + +.logintitleMemberDetail { + color: #707070; + font-weight: 600; + font-size: 20px; + margin-bottom: 30px; + padding-bottom: 5px; + border-bottom: 3px solid #eaebef; + width: 30%; +} + +.logintitleadmin { + color: #707070; + font-weight: 600; + font-size: 20px; + margin-top: 50px; + margin-bottom: 40px; + padding-bottom: 5px; + border-bottom: 3px solid #eaebef; + width: 60%; +} + +.cardBodyMemberDetail { + height: 35vh; + overflow-y: scroll; +} + +.justifyspMemberDetail { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: flex-start; + /* gap : 2px; */ +} + +.flexclm { + display: flex; + flex-direction: column; +} + +.btngroup { + display: flex; + gap: 2rem; + margin-bottom: 2rem; +} + +@media screen and (max-width: 1200px) { + .justifyspMemberDetail { + padding-left: 55px; + display: flex; + justify-content: space-evenly; + } + + .mainpageright { + width: 100%; + } + + .invitebtn { + position: relative; + right: 15px; + } +} + +.invitebtn { + border: 1px solid var(--grey-border-box-color); + box-shadow: 0 2px 2px var(--grey-border-box-color); + border-radius: 5px; + font-size: 16px; + height: 60%; + color: var(--bs-white); + outline: none; + font-weight: 600; + cursor: pointer; + transition: + transform 0.2s, + box-shadow 0.2s; + background-color: #eaebef; + margin-right: 13px; +} + +.flexdir { + display: flex; + flex-direction: row; + justify-content: space-between; + border: none; +} + +.form_wrapper { + margin-top: 27px; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + position: absolute; + display: flex; + flex-direction: column; + width: 30%; + padding: 40px 30px; + background: #ffffff; + border-color: var(--grey-border-box-color); + border-width: 5px; + border-radius: 10px; + max-height: 86vh; + overflow: auto; +} + +.form_wrapper form { + display: flex; + align-items: left; + justify-content: left; + flex-direction: column; +} + +.titlemodalMemberDetail { + color: #707070; + font-weight: 600; + font-size: 20px; + margin-bottom: 20px; + padding-bottom: 5px; + border-bottom: 3px solid #eaebef; + width: 65%; +} + +.checkboxdiv > label { + margin-right: 50px; +} + +.checkboxdiv > label > input { + margin-left: 10px; +} + +.orgphoto { + margin-top: 5px; +} + +.orgphoto > input { + margin-top: 10px; + cursor: pointer; + margin-bottom: 5px; +} + +.cancel > i { + margin-top: 5px; + transform: scale(1.2); + cursor: pointer; + color: #707070; +} + +.greenregbtnMemberDetail { + margin: 1rem 0 0; + margin-top: 10px; + border: 1px solid var(--grey-border-box-color); + box-shadow: 0 2px 2px var(--grey-border-box-color); + padding: 10px 10px; + border-radius: 5px; + background-color: #eaebef; + font-size: 16px; + color: var(--bs-white); + outline: none; + font-weight: 600; + cursor: pointer; + transition: + transform 0.2s, + box-shadow 0.2s; +} + +.whiteregbtn { + margin: 1rem 0 0; + margin-right: 2px; + margin-top: 10px; + border: 1px solid #eaebef; + padding: 10px 10px; + border-radius: 5px; + background-color: var(--bs-white); + font-size: 16px; + color: #707070; + outline: none; + font-weight: 600; + cursor: pointer; + transition: + transform 0.2s, + box-shadow 0.2s; +} + +@-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); + } +} + +.list_boxMemberDetail { + height: 70vh; + overflow-y: auto; + width: auto; + padding-right: 50px; +} + +.dispflex { + display: flex; +} + +.dispflex > input { + width: 20%; + border: none; + box-shadow: none; + margin-top: 5px; +} + +.checkboxdivMemberDetail { + display: flex; +} + +.checkboxdivMemberDetail > div { + width: 50%; +} + +@media only screen and (max-width: 600px) { + .sidebar { + position: relative; + bottom: 18px; + } + + .invitebtn { + width: 135px; + position: relative; + right: 10px; + } + + .form_wrapper { + width: 90%; + } + + .searchtitleMemberDetail { + margin-top: 30px; + } +} + +/* User page */ + +.memberfontcreatedbtn { + border-radius: 7px; + border-color: var(--grey-border-box-color); + background-color: #eaebef; + color: var(--bs-white); + box-shadow: none; + height: 2.5rem; + width: max-content; + display: flex; + justify-content: center; + align-items: center; +} + +.userImage { + width: 180px; + height: 180px; + object-fit: cover; + border-radius: 8px; +} + +@media only screen and (max-width: 1200px) { + .userImage { + width: 100px; + height: 100px; + } +} + +.activeBtn { + width: 100%; + display: flex; + color: #fff; + border: 1px solid #000; + background-color: #eaebef; + transition: 0.5s; +} + +.activeBtn:hover { + color: #fff; + background: #23864c; + transition: 0.5s; +} + +.inactiveBtn { + width: 100%; + display: flex; + color: #707070; + border: 1px solid #31bb6a60; + background-color: #fff; + transition: 0.5s; +} + +.inactiveBtn:hover { + color: #fff; + background: #eaebef; + transition: 0.5s; +} + +.sidebarstickyMemberDetail > button { + display: flex; + align-items: center; + text-align: start; + padding: 0 1.5rem; + height: 3.25rem; + margin: 0 0 1.5rem 0; + font-weight: bold; + border-radius: 50px; +} + +.bgFill { + height: 2rem; + width: 2rem; + border-radius: 50%; + margin-right: 1rem; + display: flex; + justify-content: center; + align-items: center; +} + +.activeBtn .bgFill { + background-color: #fff; +} + +.activeBtn i { + color: #707070; +} + +.inactiveBtn .bgFill { + background-color: #eaebef; +} + +.inactiveBtn:hover .bgFill { + background-color: #fff; +} + +.inactiveBtn i { + color: #fff; +} + +.inactiveBtn:hover i { + color: #707070; +} + +.topRadius { + border-top-left-radius: 16px; + border-top-right-radius: 16px; +} + +.titlenameMemberDetail { + font-weight: 600; + font-size: 25px; + padding: 15px; + padding-bottom: 0px; + width: 50%; +} + +.toporglocMemberDetail { + font-size: 16px; + padding: 15px; + padding-bottom: 0px; +} + +.toporglocMemberDetail span { + color: #737373; +} + +.inputColor { + background: #f1f3f6; +} + +.cardHeaderMemberDetail { + display: flex; + justify-content: space-between; + align-items: center; +} + +.width60 { + width: 60%; +} + +.maxWidth40 { + max-width: 40%; +} +.maxWidth50 { + max-width: 50%; +} + +.allRound { + border-radius: 16px; +} + +.WidthFit { + width: fit-content; +} + +.dateboxMemberDetail { + border-radius: 7px; + border-color: var(--grey-border-box-color); + outline: none; + box-shadow: none; + padding-top: 2px; + padding-bottom: 2px; + padding-right: 5px; + padding-left: 5px; + margin-right: 5px; + margin-left: 5px; +} + +.dateboxMemberDetail > div > input { + padding: 0.5rem 0 0.5rem 0.5rem !important; /* top, right, bottom, left */ + background-color: #f1f3f6; + border-radius: var(--bs-border-radius) !important; + border: none !important; +} + +.dateboxMemberDetail > div > div { + margin-left: 0px !important; +} + +.dateboxMemberDetail > div > fieldset { + border: none !important; + /* background-color: #f1f3f6; */ + border-radius: var(--bs-border-radius) !important; +} + +.dateboxMemberDetail > div { + margin: 0.5rem !important; + background-color: #f1f3f6; +} + +input::file-selector-button { + background-color: black; + color: var(--bs-white); +} + +.Outline { + outline: 1px solid var(--bs-gray-400); +} + +.tagLink { + font-weight: 600; + color: var(--bs-gray-700); + cursor: pointer; +} + +.tagLink:hover { + font-weight: 800; + color: var(--bs-blue); + text-decoration: underline; +} + +@media (max-width: 1440px) { + .contractOrgList { + padding-left: calc(250px + 2rem + 1.5rem); + } + + .listBoxOrgList .itemCardOrgList { + width: 100%; + } +} + +@media (max-width: 1020px) { + .btnsContainerOrgList { + flex-direction: column; + margin: 1.5rem 0; + } + + .btnsContainerOrgList .btnsBlockOrgList { + margin: 1.5rem 0 0 0; + justify-content: space-between; + } + + .btnsContainerOrgList .btnsBlockOrgList button { + margin: 0; + } + + .btnsContainerOrgList .btnsBlockOrgList div button { + margin-right: 1.5rem; + } +} + +/* For mobile devices */ + +@media (max-width: 520px) { + .btnsContainerOrgList { + margin-bottom: 0; + } + + .btnsContainerOrgList .btnsBlockOrgList { + display: block; + margin-top: 1rem; + margin-right: 0; + } + + .btnsContainerOrgList .btnsBlockOrgList div { + flex: 1; + } + + .btnsContainerOrgList .btnsBlockOrgList div[title='Sort organizations'] { + margin-right: 0.5rem; + } + + .btnsContainerOrgList .btnsBlockOrgList button { + margin-bottom: 1rem; + margin-right: 0; + width: 100%; + } +} +@media (max-width: 600px) { + .cardBody { + min-height: 120px; + } + + .cardBody .iconWrapper { + position: absolute; + top: 1rem; + left: 1rem; + } + + .cardBody .textWrapper { + margin-top: calc(0.5rem + 36px); + text-align: right; + } + + .cardBody .textWrapper .primaryText { + font-size: 1.5rem; + } + + .cardBody .textWrapper .secondaryText { + font-size: 1rem; + } +} + +.cardBody { + padding: 1.25rem 1.5rem; +} + +.cardBody .iconWrapper { + position: relative; + height: 48px; + width: 48px; + display: flex; + justify-content: center; + align-items: center; +} + +.cardBody .iconWrapper .themeOverlay { + background: var(--bs-primary); + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + opacity: 0.12; + border-radius: 50%; +} + +.cardBody .textWrapper .primaryText { + font-size: 24px; + font-weight: bold; + display: block; +} + +.cardBody .textWrapper .secondaryText { + font-size: 14px; + display: block; + color: var(--bs-secondary); +} + +/* Loading OrgList CSS */ + +.itemCardOrgList .loadingWrapper { + background-color: var(--bs-white); + margin: 0.5rem; + height: calc(120px + 2rem); + padding: 1rem; + border-radius: 8px; + outline: 1px solid var(--bs-gray-200); + position: relative; +} + +.itemCardOrgList .loadingWrapper .innerContainer { + display: flex; +} + +.itemCardOrgList .loadingWrapper .innerContainer .orgImgContainer { + width: 120px; + height: 120px; + border-radius: 4px; +} + +.itemCardOrgList .loadingWrapper .innerContainer .content { + flex: 1; + display: flex; + flex-direction: column; + margin-left: 1rem; +} + +.titlemodaldialog { + color: #707070; + font-size: 20px; + margin-bottom: 20px; + padding-bottom: 5px; +} + +form label { + font-weight: bold; + padding-bottom: 1px; + font-size: 14px; + color: #707070; +} + +form > input { + display: block; + margin-bottom: 20px; + border: 1px solid var(--grey-border-box-color); + box-shadow: 2px 1px var(--grey-border-box-color); + padding: 10px 20px; + border-radius: 5px; + background: none; + width: 100%; + transition: all 0.3s ease-in-out; + -webkit-transition: all 0.3s ease-in-out; + -moz-transition: all 0.3s ease-in-out; + -ms-transition: all 0.3s ease-in-out; + -o-transition: all 0.3s ease-in-out; +} + +.itemCardOrgList .loadingWrapper .innerContainer .content h5 { + height: 24px; + width: 60%; + margin-bottom: 0.8rem; +} + +.modalbody { + width: 50px; +} + +.pluginStoreBtnContainer { + display: flex; + gap: 1rem; +} + +.itemCardOrgList .loadingWrapper .innerContainer .content h6[title='Location'] { + display: block; + width: 45%; + height: 18px; +} + +.itemCardOrgList .loadingWrapper .innerContainer .content h6 { + display: block; + width: 30%; + height: 16px; + margin-bottom: 0.8rem; +} + +.itemCardOrgList .loadingWrapper .button { + position: absolute; + height: 48px; + width: 92px; + bottom: 1rem; + right: 1rem; + z-index: 1; +} + +.login_background { + min-height: 100vh; +} + +.communityLogo { + object-fit: contain; +} + +.row .left_portion { + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + height: 100vh; +} + +.selectOrgText input { + outline: none !important; +} + +.row .left_portion .inner .palisadoes_logo { + width: 600px; + height: auto; +} + +.row .right_portion { + min-height: 100vh; + position: relative; + overflow-y: scroll; + display: flex; + flex-direction: column; + justify-content: center; + padding: 1rem 2.5rem; + background: var(--bs-white); +} + +.row .right_portion::-webkit-scrollbar { + width: 8px; +} + +.row .right_portion::-webkit-scrollbar-track { + background: transparent; +} + +.row .right_portion::-webkit-scrollbar-thumb { + background-color: rgba(0, 0, 0, 0.2); + border-radius: 4px; +} + +.row .right_portion .langChangeBtn { + margin: 0; + position: absolute; + top: 1rem; + left: 1rem; +} + +.langChangeBtnStyle { + width: 7.5rem; + height: 2.2rem; + padding: 0; +} + +.talawa_logo { + height: clamp(3rem, 8vw, 5rem); + width: auto; + aspect-ratio: 1; + display: block; + margin: 1.5rem auto 1rem; + @media (prefers-reduced-motion: no-preference) { + -webkit-animation: zoomIn 0.3s ease-in-out; + animation: zoomIn 0.3s ease-in-out; + } +} + +.row .orText { + display: block; + position: absolute; + top: 0; + left: calc(50% - 2.6rem); + margin: 0 auto; + padding: 0.35rem 2rem; + z-index: 100; + background: var(--bs-white); + color: var(--bs-secondary); +} + +.email_button { + position: absolute; + z-index: 10; + bottom: 0; + right: 0; + height: 100%; + display: flex; + background-color: var(--search-button-bg); + border-color: var(--search-button-border); + justify-content: center; + align-items: center; +} + +.login_btn { + background-color: var(--search-button-bg); + border-color: var(--search-button-border); + margin-top: 1rem; + margin-bottom: 1rem; + width: 100%; + transition: background-color 0.2s ease; + cursor: pointer; +} + +.reg_btn { + background-color: var(--dropdown-border-color); + border-color: var(--dropdown-border-color); + margin-top: 1rem; + color: var(--bs-white); + margin-bottom: 1rem; + width: 100%; + transition: background-color 0.2s ease; + cursor: pointer; +} + +.active_tab { + -webkit-animation: fadeIn 0.3s ease-in-out; + animation: fadeIn 0.3s ease-in-out; +} + +.socialIcons { + display: flex; + gap: 16px; + justify-content: center; +} + +.password_checks { + display: flex; + justify-content: space-between; + align-items: flex-start; + flex-direction: column; + gap: var(--spacing-md, 1rem); +} + +.password_check_element { + padding: var(--spacing-sm, 0.5rem) 0; +} + +.password_check_element_top { + margin-top: var(--spacing-lg, 1.125rem); +} + +.password_check_element_bottom { + margin-bottom: var(--spacing-lg, 1.25rem); +} + +@media (max-width: 450px) { + .itemCardOrgList .loadingWrapper { + height: unset; + margin: 0.5rem 0; + padding: 1.25rem 1.5rem; + } + + .itemCardOrgList .loadingWrapper .innerContainer { + flex-direction: column; + } + + .itemCardOrgList .loadingWrapper .innerContainer .orgImgContainer { + height: 200px; + width: 100%; + margin-bottom: 0.8rem; + } + + .itemCardOrgList .loadingWrapper .innerContainer .content { + margin-left: 0; + } + + .itemCardOrgList .loadingWrapper .button { + bottom: 0; + right: 0; + border-radius: 0.5rem; + position: relative; + margin-left: auto; + display: block; + } +} + +/* * Refortoring css for Leaderboard */ + +.TableImageSmall { + object-fit: cover; + width: var(--table-image-small-size); + height: var(--table-image-small-size); + border-radius: 100%; +} + +.avatarContainer { + width: 28px; + height: 26px; +} + +.imageContainer { + display: flex; + align-items: center; + justify-content: center; + margin-right: 0.5rem; +} +/* CSS Refactor for OrgPost */ + +.btnsContainerOrgPost { + display: flex; + margin: 2.5rem 0 2.5rem 0; +} + +.btnsContainerOrgPost .btnsBlockOrgPost { + display: flex; +} + +.btnsContainerOrgPost .btnsBlockOrgPost button { + margin-left: 1rem; + display: flex; + justify-content: center; + align-items: center; +} + +.btnsContainerOrgPost .inputOrgPost { + flex: 1; + position: relative; +} + +.btnsContainerOrgPost input { + outline: 1px solid var(--bs-gray-400); +} + +.btnsContainerOrgPost .inputOrgPost button { + width: 52px; +} + +.previewOrgPost { + display: flex; + position: relative; + width: 100%; + margin-top: 10px; + justify-content: center; +} +.previewOrgPost img { + width: 400px; + height: auto; +} +.previewOrgPost video { + width: 400px; + height: auto; +} +.mainpagerightOrgPost > hr { + margin-top: 20px; + width: 100%; + margin-left: -15px; + margin-right: -15px; + margin-bottom: 20px; +} + +.pageWrapper { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100vh; +} + +.cardTemplate { + padding: 2rem; + background-color: #fff; + border-radius: 0.8rem; + border: 1px solid var(--bs-gray-200); +} + +.keyWrapper { + height: 72px; + width: 72px; + transform: rotate(180deg); + transform-origin: center; + position: relative; + overflow: hidden; + display: flex; + justify-content: center; + align-items: center; + border-radius: 50%; + margin: 1rem auto; +} + +.keyWrapper .themeOverlay { + position: absolute; + background-color: var(--bs-primary); + height: 100%; + width: 100%; + opacity: var(--theme-overlay-opacity, 0.15); +} + +.keyWrapper .keyLogo { + height: 42px; + width: 42px; + -webkit-animation: zoomIn 0.3s ease-in-out; + animation: zoomIn 0.3s ease-in-out; +} + +@media (max-width: 1020px) { + .btnsContainerOrgPost { + flex-direction: column; + margin: 1.5rem 0; + } + + .btnsContainerOrgPost .btnsBlockOrgPost { + margin: 1.5rem 0 0 0; + justify-content: space-between; + } + + .btnsContainerOrgPost .btnsBlockOrgPost button { + margin: 0; + } + + .btnsContainerOrgPost .btnsBlockOrgPost div button { + margin-right: 1.5rem; + } +} + +@media (max-width: 992px) { + .row .left_portion { + padding: 0 2rem; + } + .row .left_portion .inner .palisadoes_logo { + width: 100%; + } +} + +@media (max-width: 769px) { + .row { + flex-direction: column-reverse; + } + .row .right_portion, + .row .left_portion { + height: unset; + } + .row .right_portion { + min-height: 100vh; + overflow-y: unset; + } + .row .left_portion .inner { + display: flex; + justify-content: center; + } + .row .left_portion .inner .palisadoes_logo { + height: 70px; + width: unset; + position: absolute; + margin: 0.5rem; + top: 0; + right: 0; + z-index: 100; + } + .row .left_portion .inner p { + margin-bottom: 0; + padding: 1rem; + } + .socialIcons { + margin-bottom: 1rem; + } +} + +@media (max-width: 577px) { + .row .right_portion { + padding: 1rem 1rem 0 1rem; + } + .row .right_portion .langChangeBtn { + position: absolute; + margin: 1rem; + left: 0; + top: 0; + } + .marginTopForReg { + margin-top: 4rem !important; + } + .row .right_portion .talawa_logo { + height: 120px; + margin: 0 auto 2rem auto; + } + .socialIcons { + margin-bottom: 1rem; + } +} + +@media (prefers-reduced-motion: reduce) { + .talawa_logo { + animation: none; + } + + .active_tab { + animation: none; + } +} + +@-webkit-keyframes zoomIn { + 0% { + opacity: 0; + -webkit-transform: scale(0.5); + transform: scale(0.5); + } + 100% { + opacity: 1; + -webkit-transform: scale(1); + transform: scale(1); + } +} + +@keyframes zoomIn { + 0% { + opacity: 0; + -webkit-transform: scale(0.5); + transform: scale(0.5); + } + 100% { + opacity: 1; + -webkit-transform: scale(1); + transform: scale(1); + } +} + +@-webkit-keyframes fadeIn { + 0% { + opacity: 0; + -webkit-transform: translateY(2rem); + transform: translateY(2rem); + } + 100% { + opacity: 1; + -webkit-transform: translateY(0); + transform: translateY(0); + } +} + +@keyframes fadeIn { + 0% { + opacity: 0; + -webkit-transform: translateY(2rem); + transform: translateY(2rem); + } + 100% { + opacity: 1; + -webkit-transform: translateY(0); + transform: translateY(0); + } +} + +/* For mobile devices */ + +@media (max-width: 520px) { + .btnsContainerOrgPost { + margin-bottom: 0; + } + + .btnsContainerOrgPost .btnsBlockOrgPost { + display: block; + margin-top: 1rem; + margin-right: 0; + } + + .btnsContainerOrgPost .btnsBlockOrgPost div { + flex: 1; + } + + .btnsContainerOrgPost .btnsBlockOrgPost div[title='Sort organizations'] { + margin-right: 0.5rem; + } + + .btnsContainerOrgPost .btnsBlockOrgPost button { + margin-bottom: 1rem; + margin-right: 0; + width: 100%; + } +} +@media screen and (max-width: 575.5px) { + .mainpagerightOrgPost { + width: 98%; + } +} +.addbtnOrgPost { + border: 1px solid var(--grey-border-box-color); + box-shadow: 0 2px 2px var(--grey-border-box-color); + border-radius: 5px; + font-size: 16px; + height: 60%; + width: 60%; + color: var(--bs-white); + outline: none; + font-weight: 600; + cursor: pointer; + transition: + transform 0.2s, + box-shadow 0.2s; +} +.postinfo { + height: 80px; + margin-bottom: 20px; +} +.closeButtonOrgPost { + position: absolute; + top: 0px; + right: 0px; + background: transparent; + transform: scale(1.2); + cursor: pointer; + border: none; + color: #707070; + font-weight: 600; + font-size: 16px; +} +button[data-testid='createPostBtn'] { + display: block; +} +.loader, +.loader:after { + border-radius: 50%; + width: var(--loader-size); + height: var(--loader-size); +} +.loader { + margin: 60px auto; + margin-top: 35vh !important; + font-size: 10px; + position: relative; + text-indent: -9999em; + border-top: 1.1em solid rgba(255, 255, 255, 0.2); + border-right: 1.1em solid rgba(255, 255, 255, 0.2); + border-bottom: 1.1em solid rgba(255, 255, 255, 0.2); + border-left: 1.1em solid #febc59; + -webkit-transform: translateZ(0); + -ms-transform: translateZ(0); + transform: translateZ(0); + -webkit-animation: load8 1.1s infinite linear; + animation: load8 1.1s infinite linear; +} +@keyframes load8 { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} +.list_box { + height: 70vh; + overflow-y: auto; + width: auto; +} +@media only screen and (max-width: 600px) { + .form_wrapper { + width: 90%; + top: 45%; + } +} +.cardItem { + position: relative; + display: flex; + align-items: center; + border: 1px solid var(--bs-gray-200); + border-radius: 8px; + margin-top: 20px; +} +@-webkit-keyframes zoomIn { + 0% { + opacity: 0; + -webkit-transform: scale(0.5); + transform: scale(0.5); + } + 100% { + opacity: 1; + -webkit-transform: scale(1); + transform: scale(1); + } +} + +@keyframes zoomIn { + 0% { + opacity: 0; + -webkit-transform: scale(0.5); + transform: scale(0.5); + } + 100% { + opacity: 1; + -webkit-transform: scale(1); + transform: scale(1); + } +} + +.cardItem .iconWrapper { + position: relative; + height: 40px; + width: 40px; + display: flex; + justify-content: center; + align-items: center; +} + +.cardItem .iconWrapper .themeOverlay { + background: var(--bs-primary); + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + opacity: 0.12; + border-radius: 50%; +} + +.cardItem .title { + font-size: 1rem; + flex: 1; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; /* Fallback for browsers that don't support line-clamp */ + margin-left: 3px; +} +/* Modern browsers - enable line clamping */ +@supports (-webkit-line-clamp: 1) { + .cardItem .title, + .cardItem .location, + .cardItem .time { + display: -webkit-box; + -webkit-line-clamp: 1; + -webkit-box-orient: vertical; + white-space: initial; + } +} +.cardItem .location { + font-size: 0.9rem; + color: var(--bs-primary); + overflow: hidden; + display: -webkit-box; + -webkit-line-clamp: 1; + line-clamp: 1; + -webkit-box-orient: vertical; +} + +.cardItem .time { + font-size: 0.9rem; + color: var(--bs-secondary); +} + +.cardItem .creator { + font-size: 1rem; + color: var(--bs-success, #21d015); +} +.rightCard { + display: flex; + gap: 7px; + min-width: 170px; + justify-content: center; + flex-direction: column; + margin-left: 10px; + overflow-x: hidden; + width: 210px; + + @keyframes zoomIn { + 0% { + opacity: 0; + -webkit-transform: scale(0.5); + transform: scale(0.5); + } + + 100% { + opacity: 1; + -webkit-transform: scale(1); + transform: scale(1); + } + } + + /* AddOnEntry.tsx */ + + .entrytoggle { + margin: 24px 24px 0 auto; + width: fit-content; + } + + .entryaction { + margin-left: auto; + display: flex !important; + align-items: center; + background-color: transparent; + color: #31bb6b; + } + + .entryaction .spinner-grow { + height: 1rem; + width: 1rem; + margin-right: 8px; + } +} + +.leftDrawer { + width: calc(300px + 2rem); + position: fixed; + top: 0; + bottom: 0; + z-index: 100; + display: flex; + flex-direction: column; + padding: 1rem 1rem 0 1rem; + background-color: #f6f8fc; + transition: 0.5s; + font-family: var(--bs-leftDrawer-font-family); +} + +.activeDrawer { + width: calc(300px + 2rem); + position: fixed; + top: 0; + left: 0; + bottom: 0; + animation: comeToRightBigScreen 0.5s ease-in-out; +} + +.inactiveDrawer { + position: fixed; + top: 0; + left: calc(-300px - 2rem); + bottom: 0; + animation: goToLeftBigScreen 0.5s ease-in-out; +} + +.leftDrawer .talawaLogo { + width: 100%; + height: 65px; +} + +.leftDrawer .talawaText { + font-size: 20px; + text-align: center; + font-weight: 500; +} + +.leftDrawer .titleHeader { + margin: 2rem 0 1rem 0; + font-weight: 600; +} + +.leftDrawer .optionList button { + display: flex; + align-items: center; + width: 100%; + text-align: start; + margin-bottom: 0.8rem; + border-radius: 16px; + outline: none; + border: none; +} + +.leftDrawer .optionList button .iconWrapper { + width: 36px; +} + +.leftDrawer .profileContainer { + border: none; + width: 100%; + padding: 2.1rem 0.5rem; + height: 52px; + display: flex; + align-items: center; + background-color: var(--bs-white); +} + +.leftDrawer .profileContainer:focus { + outline: none; + background-color: var(--bs-gray-100); +} + +.leftDrawer .imageContainer { + width: 68px; +} + +.leftDrawer .profileContainer img { + height: 52px; + width: 52px; + border-radius: 50%; +} + +.leftDrawer .profileContainer .profileText { + flex: 1; + text-align: start; +} + +.leftDrawer .profileContainer .profileText .primaryText { + font-size: 1.1rem; + font-weight: 600; +} + +.leftDrawer .profileContainer .profileText .secondaryText { + font-size: 0.8rem; + font-weight: 400; + color: var(--bs-secondary); + display: block; + text-transform: capitalize; +} + +@media (max-width: 1120px) { + .leftDrawer { + width: calc(250px + 2rem); + padding: 1rem 1rem 0 1rem; + } +} + +/* For tablets */ +@media (max-width: 820px) { + .hideElemByDefault { + display: none; + } + + .leftDrawer { + width: 100%; + left: 0; + right: 0; + } + + .inactiveDrawer { + opacity: 0; + left: 0; + z-index: -1; + animation: closeDrawer 0.4s ease-in-out; + } + + .activeDrawer { + display: flex; + z-index: 100; + animation: openDrawer 0.6s ease-in-out; + } + + .logout { + margin-bottom: 2.5rem !important; + } +} + +@keyframes goToLeftBigScreen { + from { + left: 0; + } + + to { + opacity: 0.1; + left: calc(-300px - 2rem); + } +} + +/* Webkit prefix for older browser compatibility */ +@-webkit-keyframes goToLeftBigScreen { + from { + left: 0; + } + + to { + opacity: 0.1; + left: calc(-300px - 2rem); + } +} + +@keyframes comeToRightBigScreen { + from { + opacity: 0.4; + left: calc(-300px - 2rem); + } + + to { + opacity: 1; + left: 0; + } +} + +/* Webkit prefix for older browser compatibility */ +@-webkit-keyframes comeToRightBigScreen { + from { + opacity: 0.4; + left: calc(-300px - 2rem); + } + + to { + opacity: 1; + left: 0; + } +} + +@keyframes closeDrawer { + from { + left: 0; + opacity: 1; + } + + to { + left: -1000px; + opacity: 0; + } +} + +/* Webkit prefix for older browser compatibility */ +@-webkit-keyframes closeDrawer { + from { + left: 0; + opacity: 1; + } + + to { + left: -1000px; + opacity: 0; + } +} + +@keyframes openDrawer { + from { + opacity: 0; + left: -1000px; + } + + to { + left: 0; + opacity: 1; + } +} + +/* Webkit prefix for older browser compatibility */ +@-webkit-keyframes openDrawer { + from { + opacity: 0; + left: -1000px; + } + to { + left: 0; + opacity: 1; + } +} diff --git a/src/utils/chartToPdf.spec.ts b/src/utils/chartToPdf.spec.ts new file mode 100644 index 0000000000..e1ab67fdb0 --- /dev/null +++ b/src/utils/chartToPdf.spec.ts @@ -0,0 +1,153 @@ +import { expect, describe, test, beforeEach, afterEach, vi } from 'vitest'; +import type { Mock } from 'vitest'; +import { + exportToCSV, + exportTrendsToCSV, + exportDemographicsToCSV, +} from './chartToPdf'; + +describe('CSV Export Functions', () => { + // Define more specific types for our mocks + let mockCreateElement: Mock; + let mockAppendChild: Mock; + let mockRemoveChild: Mock; + let mockClick: Mock; + let mockSetAttribute: Mock; + let mockLink: HTMLAnchorElement; + + beforeEach(() => { + // Mock URL methods with specific types + (global.URL.createObjectURL as unknown) = vi.fn(() => 'mock-url'); + (global.URL.revokeObjectURL as unknown) = vi.fn(); + + // Mock DOM methods + mockSetAttribute = vi.fn(); + mockClick = vi.fn(); + mockLink = { + setAttribute: mockSetAttribute, + click: mockClick, + parentNode: document.body, + } as unknown as HTMLAnchorElement; + + // Mock createElement with proper type assertion + mockCreateElement = vi.fn().mockReturnValue(mockLink); + document.createElement = + mockCreateElement as unknown as typeof document.createElement; + + // Mock appendChild and removeChild with proper type assertions + mockAppendChild = vi.fn().mockReturnValue(mockLink); + mockRemoveChild = vi.fn().mockReturnValue(mockLink); + + document.body.appendChild = + mockAppendChild as unknown as typeof document.body.appendChild; + document.body.removeChild = + mockRemoveChild as unknown as typeof document.body.removeChild; + }); + + afterEach(() => { + vi.clearAllMocks(); + }); + + test('exports data to CSV with proper formatting', () => { + const data: string[][] = [ + ['Header1', 'Header2'], + ['Value1', 'Value2'], + ['Value with, comma', 'Value with "quotes"'], + ]; + + exportToCSV(data, 'test.csv'); + + expect(mockCreateElement).toHaveBeenCalledWith('a'); + expect(mockSetAttribute).toHaveBeenCalledWith('href', 'mock-url'); + expect(mockSetAttribute).toHaveBeenCalledWith('download', 'test.csv'); + expect(mockAppendChild).toHaveBeenCalled(); + expect(mockClick).toHaveBeenCalled(); + expect(mockRemoveChild).toHaveBeenCalled(); + expect(URL.revokeObjectURL).toHaveBeenCalledWith('mock-url'); + }); + + test('throws error if data is empty', () => { + expect(() => exportToCSV([], 'test.csv')).toThrow('Data cannot be empty'); + }); + + test('throws error if filename is empty', () => { + expect(() => exportToCSV([['data']], '')).toThrow('Filename is required'); + }); + + test('adds .csv extension if missing', () => { + const data = [['test']]; + exportToCSV(data, 'filename'); + expect(mockSetAttribute).toHaveBeenCalledWith('download', 'filename.csv'); + }); + + describe('exportTrendsToCSV', () => { + test('exports attendance trends data correctly', () => { + const eventLabels: string[] = ['Event1', 'Event2']; + const attendeeCounts: number[] = [10, 20]; + const maleCounts: number[] = [5, 10]; + const femaleCounts: number[] = [4, 8]; + const otherCounts: number[] = [1, 2]; + + exportTrendsToCSV( + eventLabels, + attendeeCounts, + maleCounts, + femaleCounts, + otherCounts, + ); + + expect(mockCreateElement).toHaveBeenCalledWith('a'); + expect(mockSetAttribute).toHaveBeenCalledWith( + 'download', + 'attendance_trends.csv', + ); + expect(mockClick).toHaveBeenCalled(); + }); + }); + + describe('exportDemographicsToCSV', () => { + test('exports demographics data correctly', () => { + const selectedCategory = 'Age Groups'; + const categoryLabels: string[] = ['0-18', '19-30', '31+']; + const categoryData: number[] = [10, 20, 15]; + + exportDemographicsToCSV(selectedCategory, categoryLabels, categoryData); + + expect(mockCreateElement).toHaveBeenCalledWith('a'); + expect(mockClick).toHaveBeenCalled(); + expect(mockSetAttribute).toHaveBeenCalledWith('href', 'mock-url'); + }); + + test('throws error if selected category is empty', () => { + expect(() => exportDemographicsToCSV('', ['label'], [1])).toThrow( + 'Selected category is required', + ); + }); + + test('throws error if labels and data arrays have different lengths', () => { + expect(() => + exportDemographicsToCSV('Category', ['label1', 'label2'], [1]), + ).toThrow('Labels and data arrays must have the same length'); + }); + + test('creates safe filename with timestamp', () => { + vi.useFakeTimers(); + const mockDate = new Date('2023-01-01T00:00:00.000Z'); + vi.setSystemTime(mockDate); + + const selectedCategory = 'Age & Demographics!'; + const categoryLabels = ['Group1']; + const categoryData = [10]; + + exportDemographicsToCSV(selectedCategory, categoryLabels, categoryData); + + const expectedFilename = + 'age___demographics__demographics_2023-01-01T00-00-00.000Z.csv'; + const downloadCalls = mockSetAttribute.mock.calls.filter( + (call) => call[0] === 'download', + ); + expect(downloadCalls[0][1]).toBe(expectedFilename); + vi.useRealTimers(); + }); + }); +}); diff --git a/src/utils/chartToPdf.ts b/src/utils/chartToPdf.ts new file mode 100644 index 0000000000..d724f077cc --- /dev/null +++ b/src/utils/chartToPdf.ts @@ -0,0 +1,106 @@ +type CSVData = (string | number)[][]; + +export const exportToCSV = (data: CSVData, filename: string): void => { + if (!data?.length) { + throw new Error('Data cannot be empty'); + } + + if (!filename) { + throw new Error('Filename is required'); + } + + // Ensure .csv extension + const finalFilename = filename.endsWith('.csv') + ? filename + : `${filename}.csv`; + const csvContent = + // Properly escape and quote CSV content + 'data:text/csv;charset=utf-8,' + + data + .map((row) => + row + .map((cell) => { + const cellStr = String(cell); + // Escape double quotes by doubling them + const escapedCell = cellStr.replace(/"/g, '""'); + // Enclose cell in double quotes if it contains commas, newlines, or double quotes + return /[",\n]/.test(escapedCell) + ? `"${escapedCell}"` + : escapedCell; + }) + .join(','), + ) + .join('\n'); + const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' }); + const url = URL.createObjectURL(blob); + const link = document.createElement('a'); + try { + link.setAttribute('href', url); + link.setAttribute('download', finalFilename); + document.body.appendChild(link); + link.click(); + } finally { + if (link.parentNode === document.body) { + document.body.removeChild(link); + } + URL.revokeObjectURL(url); // Clean up the URL object + } +}; + +export const exportTrendsToCSV = ( + eventLabels: string[], + attendeeCounts: number[], + maleCounts: number[], + femaleCounts: number[], + otherCounts: number[], +): void => { + const heading = 'Attendance Trends'; + const headers = [ + 'Date', + 'Attendee Count', + 'Male Attendees', + 'Female Attendees', + 'Other Attendees', + ]; + const data: CSVData = [ + [heading], + [], + headers, + ...eventLabels.map((label, index) => [ + label, + attendeeCounts[index], + maleCounts[index], + femaleCounts[index], + otherCounts[index], + ]), + ]; + exportToCSV(data, 'attendance_trends.csv'); +}; + +export const exportDemographicsToCSV = ( + selectedCategory: string, + categoryLabels: string[], + categoryData: number[], +): void => { + if (!selectedCategory?.trim()) { + throw new Error('Selected category is required'); + } + + if (categoryLabels.length !== categoryData.length) { + throw new Error('Labels and data arrays must have the same length'); + } + + const heading = `${selectedCategory} Demographics`; + const headers = [selectedCategory, 'Count']; + const data: CSVData = [ + [heading], + [], + headers, + ...categoryLabels.map((label, index) => [label, categoryData[index]]), + ]; + const safeCategory = selectedCategory + .replace(/[^a-z0-9]/gi, '_') + .toLowerCase(); + const timestamp = new Date().toISOString().replace(/[:]/g, '-'); + exportToCSV(data, `${safeCategory}_demographics_${timestamp}.csv`); +}; diff --git a/src/utils/convertToBase64.test.ts b/src/utils/convertToBase64.spec.ts similarity index 90% rename from src/utils/convertToBase64.test.ts rename to src/utils/convertToBase64.spec.ts index 51198ccc29..85b97ac31a 100644 --- a/src/utils/convertToBase64.test.ts +++ b/src/utils/convertToBase64.spec.ts @@ -1,3 +1,4 @@ +import { describe, it, expect, vi } from 'vitest'; import convertToBase64 from './convertToBase64'; describe('convertToBase64', () => { @@ -16,7 +17,7 @@ describe('convertToBase64', () => { it('should handle errors thrown by FileReader', async () => { // Arrange const file = new File(['hello'], 'hello.txt', { type: 'text/plain' }); - const mockFileReader = jest + const mockFileReader = vi .spyOn(global, 'FileReader') .mockImplementationOnce(() => { throw new Error('Test error'); @@ -29,5 +30,6 @@ describe('convertToBase64', () => { expect(mockFileReader).toHaveBeenCalledTimes(1); expect(mockFileReader).toHaveBeenCalledWith(); expect(result).toBe(''); + mockFileReader.mockRestore(); }); }); diff --git a/src/utils/dateFormatter.test.ts b/src/utils/dateFormatter.test.ts new file mode 100644 index 0000000000..a8e2b4b096 --- /dev/null +++ b/src/utils/dateFormatter.test.ts @@ -0,0 +1,37 @@ +import { formatDate } from './dateFormatter'; + +describe('formatDate', () => { + test('formats date with st suffix', () => { + expect(formatDate('2023-01-01')).toBe('1st Jan 2023'); + expect(formatDate('2023-05-21')).toBe('21st May 2023'); + expect(formatDate('2023-10-31')).toBe('31st Oct 2023'); + }); + + test('formats date with nd suffix', () => { + expect(formatDate('2023-06-02')).toBe('2nd Jun 2023'); + expect(formatDate('2023-09-22')).toBe('22nd Sep 2023'); + }); + + test('formats date with rd suffix', () => { + expect(formatDate('2023-07-03')).toBe('3rd Jul 2023'); + expect(formatDate('2023-08-23')).toBe('23rd Aug 2023'); + }); + + test('formats date with th suffix', () => { + expect(formatDate('2023-02-04')).toBe('4th Feb 2023'); + expect(formatDate('2023-03-11')).toBe('11th Mar 2023'); + expect(formatDate('2023-04-12')).toBe('12th Apr 2023'); + expect(formatDate('2023-05-13')).toBe('13th May 2023'); + expect(formatDate('2023-06-24')).toBe('24th Jun 2023'); + }); + + test('throws error for empty date string', () => { + expect(() => formatDate('')).toThrow('Date string is required'); + }); + + test('throws error for invalid date string', () => { + expect(() => formatDate('invalid-date')).toThrow( + 'Invalid date string provided', + ); + }); +}); diff --git a/src/utils/dateFormatter.ts b/src/utils/dateFormatter.ts new file mode 100644 index 0000000000..92f4abc051 --- /dev/null +++ b/src/utils/dateFormatter.ts @@ -0,0 +1,33 @@ +export function formatDate(dateString: string): string { + if (!dateString) { + throw new Error('Date string is required'); + } + const date = new Date(dateString); + if (isNaN(date.getTime())) { + throw new Error('Invalid date string provided'); + } + const day = date.getDate(); + const year = date.getFullYear(); + + const getSuffix = (day: number): string => { + if (day >= 11 && day <= 13) return 'th'; + const lastDigit = day % 10; + switch (lastDigit) { + case 1: + return 'st'; + case 2: + return 'nd'; + case 3: + return 'rd'; + default: + return 'th'; + } + }; + const suffix = getSuffix(day); + + const monthName = new Intl.DateTimeFormat('en', { month: 'short' }).format( + date, + ); + + return `${day}${suffix} ${monthName} ${year}`; +} diff --git a/src/utils/errorHandler.spec.tsx b/src/utils/errorHandler.spec.tsx new file mode 100644 index 0000000000..96c35e2a7f --- /dev/null +++ b/src/utils/errorHandler.spec.tsx @@ -0,0 +1,104 @@ +type TFunction = (key: string, options?: Record) => string; + +import { errorHandler } from './errorHandler'; +import { toast } from 'react-toastify'; +import { describe, it, expect, vi } from 'vitest'; + +vi.mock('react-toastify', () => ({ + toast: { + error: vi.fn(), + }, +})); + +describe('Test if errorHandler is working properly', () => { + const t: TFunction = (key: string) => key; + const tErrors: TFunction = ( + key: string, + options?: Record, + ) => { + if (options) { + console.log(`options are passed, but the function returns only ${key}`); + } + return key; + }; + + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('should call toast.error with the correct message if error message is "Failed to fetch"', async () => { + const error = new Error('Failed to fetch'); + errorHandler(t, error); + + expect(toast.error).toHaveBeenCalledWith(tErrors('talawaApiUnavailable')); + }); + + it('should call toast.error with the correct message if error message contains this substring "Value is not a valid phone number"', () => { + const error = new Error('This value is not a valid phone number'); + errorHandler(t, error); + expect(toast.error).toHaveBeenCalledWith(tErrors('invalidPhoneNumber')); + }); + + test.each([ + ['EducationGrade', 'invalidEducationGrade'], + ['EmploymentStatus', 'invalidEmploymentStatus'], + ['MaritalStatus', 'invalidMaritalStatus'], + ])('should handle invalid %s error', (field, expectedKey) => { + const error = new Error(`This value does not exist in "${field}"`); + errorHandler(t, error); + expect(toast.error).toHaveBeenCalledWith(tErrors(expectedKey)); + }); + + it('should call toast.error with the correct message if error message contains this substring "status code 400"', () => { + const error = new Error('Server responded with status code 400'); + errorHandler(t, error); + + expect(toast.error).toHaveBeenCalledWith(tErrors('error400')); + }); + + it('should handle error messages with different cases', () => { + errorHandler(t, new Error('VALUE IS NOT A VALID PHONE NUMBER')); + expect(toast.error).toHaveBeenCalledWith(tErrors('invalidPhoneNumber')); + + errorHandler(t, new Error('This Value Does Not Exist in "EducationGrade"')); + expect(toast.error).toHaveBeenCalledWith(tErrors('invalidEducationGrade')); + }); + + it('should call toast.error with the error message if it is an instance of error but have not matched any error message patterns', () => { + const error = new Error('Bandhan sent an error message'); + errorHandler(t, error); + expect(toast.error).toHaveBeenCalledWith(error.message); + }); + + it('should handle different types for the first parameter while still showing error messages', () => { + errorHandler(undefined, new Error('Some error')); + expect(toast.error).toHaveBeenCalled(); + + errorHandler(null, new Error('Some error')); + expect(toast.error).toHaveBeenCalled(); + + errorHandler({}, new Error('Some error')); + expect(toast.error).toHaveBeenCalled(); + }); + + it('should handle non-null but non-Error objects for the error parameter', () => { + errorHandler(t, { message: 'Error message in object' }); + expect(toast.error).toHaveBeenCalledWith( + tErrors('unknownError', { msg: { message: 'Error message in object' } }), + ); + + errorHandler(t, 'Direct error message'); + expect(toast.error).toHaveBeenCalledWith( + tErrors('unknownError', { msg: 'Direct error message' }), + ); + }); + + it('should call toast.error with the error message if error object is falsy', () => { + const error = null; + errorHandler(t, error); + + expect(toast.error).toHaveBeenCalledWith( + tErrors('unknownError', { msg: error }), + ); + }); +}); diff --git a/src/utils/errorHandler.test.tsx b/src/utils/errorHandler.test.tsx deleted file mode 100644 index 45f46e6389..0000000000 --- a/src/utils/errorHandler.test.tsx +++ /dev/null @@ -1,39 +0,0 @@ -type TFunction = (key: string, options?: Record) => string; - -import { errorHandler } from './errorHandler'; -import { toast } from 'react-toastify'; - -jest.mock('react-toastify', () => ({ - toast: { - error: jest.fn(), - }, -})); - -describe('Test if errorHandler is working properly', () => { - 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'); - errorHandler(t, error); - - expect(toast.error).toHaveBeenCalledWith(tErrors('talawaApiUnavailable')); - }); - - it('should call toast.error with the error message if it is not "Failed to fetch"', () => { - const error = new Error('Some other error message'); - errorHandler(t, error); - - expect(toast.error).toHaveBeenCalledWith(error.message); - }); - - it('should call toast.error with the error message if error object is falsy', () => { - const error = null; - errorHandler(t, error); - - expect(toast.error).toHaveBeenCalledWith( - tErrors('unknownError', { msg: error }), - ); - }); -}); diff --git a/src/utils/errorHandler.tsx b/src/utils/errorHandler.tsx index b7a22210a8..e4e543e940 100644 --- a/src/utils/errorHandler.tsx +++ b/src/utils/errorHandler.tsx @@ -5,18 +5,26 @@ 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. + If the error is due to the Talawa API being unavailable, it displays a custom message. And for other error cases, it is using regular expression (case-insensitive) to match and show valid messages */ export const errorHandler = (a: unknown, error: unknown): void => { const tErrors: TFunction = i18n.getFixedT(null, 'errors'); if (error instanceof Error) { - switch (error.message) { - case 'Failed to fetch': - toast.error(tErrors('talawaApiUnavailable') as string); - break; - // Add more cases as needed - default: - toast.error(error.message); + const errorMessage = error.message; + if (errorMessage === 'Failed to fetch') { + toast.error(tErrors('talawaApiUnavailable')); + } else if (errorMessage.match(/value is not a valid phone number/i)) { + toast.error(tErrors('invalidPhoneNumber')); + } else if (errorMessage.match(/does not exist in "EducationGrade"/i)) { + toast.error(tErrors('invalidEducationGrade')); + } else if (errorMessage.match(/does not exist in "EmploymentStatus"/i)) { + toast.error(tErrors('invalidEmploymentStatus')); + } else if (errorMessage.match(/does not exist in "MaritalStatus"/i)) { + toast.error(tErrors('invalidMaritalStatus')); + } else if (errorMessage.match(/status code 400/i)) { + toast.error(tErrors('error400')); + } else { + toast.error(errorMessage); } } else { toast.error(tErrors('unknownError', { msg: error }) as string); diff --git a/src/utils/formEnumFields.ts b/src/utils/formEnumFields.ts index 928537aaab..03b033f185 100644 --- a/src/utils/formEnumFields.ts +++ b/src/utils/formEnumFields.ts @@ -202,124 +202,124 @@ const countryOptions = [ const educationGradeEnum = [ { value: 'NO_GRADE', - label: 'noGrade', + label: 'No-Grade', }, { value: 'PRE_KG', - label: 'preKg', + label: 'Pre-Kg', }, { value: 'KG', - label: 'kg', + label: 'Kg', }, { value: 'GRADE_1', - label: 'grade1', + label: 'Grade-1', }, { value: 'GRADE_2', - label: 'grade2', + label: 'Grade-2', }, { value: 'GRADE_3', - label: 'grade3', + label: 'Grade-3', }, { value: 'GRADE_4', - label: 'grade4', + label: 'Grade-4', }, { value: 'GRADE_5', - label: 'grade5', + label: 'Grade-5', }, { value: 'GRADE_6', - label: 'grade6', + label: 'Grade-6', }, { value: 'GRADE_7', - label: 'grade7', + label: 'Grade-7', }, { value: 'GRADE_8', - label: 'grade8', + label: 'Grade-8', }, { value: 'GRADE_9', - label: 'grade9', + label: 'Grade-9', }, { value: 'GRADE_10', - label: 'grade10', + label: 'Grade-10', }, { value: 'GRADE_11', - label: 'grade11', + label: 'Grade-11', }, { value: 'GRADE_12', - label: 'grade12', + label: 'Grade-12', }, { value: 'GRADUATE', - label: 'graduate', + label: 'Graduate', }, ]; const maritalStatusEnum = [ { value: 'SINGLE', - label: 'single', + label: 'Single', }, { value: 'ENGAGED', - label: 'engaged', + label: 'Engaged', }, { value: 'MARRIED', - label: 'married', + label: 'Married', }, { value: 'DIVORCED', - label: 'divorced', + label: 'Divorced', }, { value: 'WIDOWED', - label: 'widowed', + label: 'Widowed', }, { value: 'SEPARATED', - label: 'separated', + label: 'Separated', }, ]; const genderEnum = [ { value: 'MALE', - label: 'male', + label: 'Male', }, { value: 'FEMALE', - label: 'female', + label: 'Female', }, { value: 'OTHER', - label: 'other', + label: 'Other', }, ]; const employmentStatusEnum = [ { value: 'FULL_TIME', - label: 'fullTime', + label: 'Full-Time', }, { value: 'PART_TIME', - label: 'partTime', + label: 'Part-Time', }, { value: 'UNEMPLOYED', - label: 'unemployed', + label: 'Unemployed', }, ]; diff --git a/src/utils/getRefreshToken.spec.ts b/src/utils/getRefreshToken.spec.ts new file mode 100644 index 0000000000..54ed1b57e8 --- /dev/null +++ b/src/utils/getRefreshToken.spec.ts @@ -0,0 +1,87 @@ +// SKIP_LOCALSTORAGE_CHECK +import { describe, it, expect, beforeEach, vi } from 'vitest'; +import { refreshToken } from './getRefreshToken'; + +const mockApolloClient = { + mutate: vi.fn(() => + Promise.resolve({ + data: { + refreshToken: { + accessToken: 'newAccessToken', + refreshToken: 'newRefreshToken', + }, + }, + }), + ), +}; + +vi.mock('@apollo/client', async () => { + const actual = await vi.importActual('@apollo/client'); + return { + ...actual, + ApolloClient: vi.fn(() => mockApolloClient), + }; +}); + +describe('refreshToken', () => { + const { location } = window; + + interface TestInterfacePartialWindow { + location?: Partial; + } + + delete (window as TestInterfacePartialWindow).location; + global.window.location = { ...location, reload: vi.fn() }; + + // Create storage mock + const localStorageMock = { + getItem: vi.fn(), + setItem: vi.fn(), + clear: vi.fn(), + removeItem: vi.fn(), + length: 0, + key: vi.fn(), + }; + + beforeEach(() => { + vi.clearAllMocks(); + Object.defineProperty(window, 'localStorage', { + value: localStorageMock, + writable: true, + }); + }); + + it('returns true when the token is refreshed successfully', async () => { + const result = await refreshToken(); + + expect(localStorage.setItem).toHaveBeenCalledWith( + 'Talawa-admin_token', + JSON.stringify('newAccessToken'), + ); + expect(localStorage.setItem).toHaveBeenCalledWith( + 'Talawa-admin_refreshToken', + JSON.stringify('newRefreshToken'), + ); + expect(result).toBe(true); + expect(window.location.reload).toHaveBeenCalled(); + }); + + it('returns false and logs error when token refresh fails', async () => { + const consoleErrorSpy = vi + .spyOn(console, 'error') + .mockImplementation(() => {}); + + const errorMock = new Error('Failed to refresh token'); + mockApolloClient.mutate.mockRejectedValueOnce(errorMock); + + const result = await refreshToken(); + + expect(result).toBe(false); + expect(consoleErrorSpy).toHaveBeenCalledWith( + 'Failed to refresh token', + errorMock, + ); + + consoleErrorSpy.mockRestore(); + }); +}); diff --git a/src/utils/getRefreshToken.test.ts b/src/utils/getRefreshToken.test.ts deleted file mode 100644 index 58de898a66..0000000000 --- a/src/utils/getRefreshToken.test.ts +++ /dev/null @@ -1,54 +0,0 @@ -// SKIP_LOCALSTORAGE_CHECK -import { refreshToken } from './getRefreshToken'; - -jest.mock('@apollo/client', () => { - const originalModule = jest.requireActual('@apollo/client'); - - return { - __esModule: true, - ...originalModule, - ApolloClient: jest.fn(() => ({ - mutate: jest.fn(() => - Promise.resolve({ - data: { - refreshToken: { - accessToken: 'newAccessToken', - refreshToken: 'newRefreshToken', - }, - }, - }), - ), - })), - }; -}); - -describe('refreshToken', () => { - // Mock window.location.reload() - const { location } = window; - delete (global.window as any).location; - global.window.location = { ...location, reload: jest.fn() }; - - // Mock localStorage.setItem() and localStorage.clear() - - Storage.prototype.setItem = jest.fn(); - Storage.prototype.clear = jest.fn(); - - beforeEach(() => { - jest.clearAllMocks(); - }); - - it('returns true when the token is refreshed successfully', async () => { - const result = await refreshToken(); - - expect(localStorage.setItem).toHaveBeenCalledWith( - 'Talawa-admin_token', - JSON.stringify('newAccessToken'), - ); - expect(localStorage.setItem).toHaveBeenCalledWith( - 'Talawa-admin_refreshToken', - JSON.stringify('newRefreshToken'), - ); - expect(result).toBe(true); - expect(window.location.reload).toHaveBeenCalled(); - }); -}); diff --git a/src/utils/getRefreshToken.ts b/src/utils/getRefreshToken.ts index 5d6f8aa2ce..90b1b55ef1 100644 --- a/src/utils/getRefreshToken.ts +++ b/src/utils/getRefreshToken.ts @@ -14,7 +14,7 @@ export async function refreshToken(): Promise { const { getItem, setItem } = useLocalStorage(); const refreshToken = getItem('refreshToken'); - /* istanbul ignore next */ + try { const { data } = await client.mutate({ mutation: REFRESH_TOKEN_MUTATION, diff --git a/src/utils/interfaces.ts b/src/utils/interfaces.ts index 495234a5a1..7ab84a61c1 100644 --- a/src/utils/interfaces.ts +++ b/src/utils/interfaces.ts @@ -7,6 +7,27 @@ export interface InterfaceUserType { }; } +export interface InterfaceUserInfo { + _id: string; + firstName: string; + lastName: string; + image?: string | null; +} + +// Base interface for common event properties +export interface InterfaceBaseEvent { + _id: string; + title: string; + description: string; + startDate: string; + endDate: string; + location: string; + startTime: string; + endTime: string; + allDay: boolean; + recurring: boolean; +} + export interface InterfaceActionItemCategoryInfo { _id: string; name: string; @@ -21,18 +42,11 @@ export interface InterfaceActionItemCategoryList { export interface InterfaceActionItemInfo { _id: string; - assignee: { - _id: string; - firstName: string; - lastName: string; - image: string | null; - }; - assigner: { - _id: string; - firstName: string; - lastName: string; - image: string | null; - }; + assigneeType: 'EventVolunteer' | 'EventVolunteerGroup' | 'User'; + assignee: InterfaceEventVolunteerInfo | null; + assigneeGroup: InterfaceVolunteerGroupInfo | null; + assigneeUser: InterfaceUserInfo | null; + assigner: InterfaceUserInfo; actionItemCategory: { _id: string; name: string; @@ -41,18 +55,14 @@ export interface InterfaceActionItemInfo { postCompletionNotes: string | null; assignmentDate: Date; dueDate: Date; - completionDate: Date; + completionDate: Date | null; isCompleted: boolean; event: { _id: string; title: string; } | null; - creator: { - _id: string; - firstName: string; - lastName: string; - }; - allotedHours: number | null; + creator: InterfaceUserInfo; + allottedHours: number | null; } export interface InterfaceActionItemList { @@ -209,19 +219,43 @@ export interface InterfaceQueryOrganizationPostListItem { }; } -interface InterfaceTagData { +export interface InterfaceTagData { + _id: string; + name: string; + parentTag: { _id: string }; + usersAssignedTo: { + totalCount: number; + }; + childTags: { + totalCount: number; + }; + ancestorTags: { + _id: string; + name: string; + }[]; +} + +interface InterfaceTagNodeData { + edges: { + node: InterfaceTagData; + cursor: string; + }[]; + pageInfo: { + startCursor: string; + endCursor: string; + hasNextPage: boolean; + hasPreviousPage: boolean; + }; + totalCount: number; +} + +interface InterfaceTagMembersData { edges: { node: { _id: string; - name: string; - usersAssignedTo: { - totalCount: number; - }; - childTags: { - totalCount: number; - }; + firstName: string; + lastName: string; }; - cursor: string; }[]; pageInfo: { startCursor: string; @@ -233,32 +267,30 @@ interface InterfaceTagData { } export interface InterfaceQueryOrganizationUserTags { - userTags: InterfaceTagData; + userTags: InterfaceTagNodeData; +} + +export interface InterfaceQueryUserTagChildTags { + name: string; + childTags: InterfaceTagNodeData; + ancestorTags: { + _id: string; + name: string; + }[]; } export interface InterfaceQueryUserTagsAssignedMembers { name: string; - usersAssignedTo: { - edges: { - node: { - _id: string; - firstName: string; - lastName: string; - }; - }[]; - pageInfo: { - startCursor: string; - endCursor: string; - hasNextPage: boolean; - hasPreviousPage: boolean; - }; - totalCount: number; - }; + usersAssignedTo: InterfaceTagMembersData; + ancestorTags: { + _id: string; + name: string; + }[]; } -export interface InterfaceQueryUserTagChildTags { +export interface InterfaceQueryUserTagsMembersToAssignTo { name: string; - childTags: InterfaceTagData; + usersToAssignTo: InterfaceTagMembersData; } export interface InterfaceQueryOrganizationAdvertisementListItem { @@ -343,19 +375,10 @@ export interface InterfacePledgeInfo { currency: string; endDate: string; startDate: string; - users: InterfacePledger[]; + users: InterfaceUserInfo[]; } -export interface InterfaceQueryOrganizationEventListItem { - _id: string; - title: string; - description: string; - startDate: string; - endDate: string; - location: string; - startTime: string; - endTime: string; - allDay: boolean; - recurring: boolean; +export interface InterfaceQueryOrganizationEventListItem + extends InterfaceBaseEvent { isPublic: boolean; isRegisterable: boolean; } @@ -483,7 +506,7 @@ export interface InterfacePostCard { } export interface InterfaceCreatePledge { - pledgeUsers: InterfacePledger[]; + pledgeUsers: InterfaceUserInfo[]; pledgeAmount: number; pledgeCurrency: string; pledgeStartDate: Date; @@ -505,13 +528,6 @@ export interface InterfaceQueryMembershipRequestsListItem { }[]; } -export interface InterfacePledger { - _id: string; - firstName: string; - lastName: string; - image: string | null; -} - export interface InterfaceAgendaItemCategoryInfo { _id: string; name: string; @@ -527,6 +543,20 @@ export interface InterfaceAgendaItemCategoryList { agendaItemCategoriesByOrganization: InterfaceAgendaItemCategoryInfo[]; } +export interface InterfaceAddOnSpotAttendeeProps { + show: boolean; + handleClose: () => void; + reloadMembers: () => void; +} + +export interface InterfaceFormData { + firstName: string; + lastName: string; + email: string; + phoneNo: string; + gender: string; +} + export interface InterfaceAgendaItemInfo { _id: string; title: string; @@ -571,3 +601,101 @@ export interface InterfaceCustomFieldData { type: string; name: string; } + +export interface InterfaceEventVolunteerInfo { + _id: string; + hasAccepted: boolean; + hoursVolunteered: number | null; + user: InterfaceUserInfo; + assignments: { + _id: string; + }[]; + groups: { + _id: string; + name: string; + volunteers: { + _id: string; + }[]; + }[]; +} + +export interface InterfaceVolunteerGroupInfo { + _id: string; + name: string; + description: string | null; + event: { + _id: string; + }; + volunteersRequired: number | null; + createdAt: string; + creator: InterfaceUserInfo; + leader: InterfaceUserInfo; + volunteers: { + _id: string; + user: InterfaceUserInfo; + }[]; + assignments: { + _id: string; + actionItemCategory: { + _id: string; + name: string; + }; + allottedHours: number; + isCompleted: boolean; + }[]; +} + +export interface InterfaceCreateVolunteerGroup { + name: string; + description: string | null; + leader: InterfaceUserInfo | null; + volunteersRequired: number | null; + volunteerUsers: InterfaceUserInfo[]; +} + +export interface InterfaceUserEvents extends InterfaceBaseEvent { + volunteerGroups: { + _id: string; + name: string; + volunteersRequired: number; + description: string; + volunteers: { _id: string }[]; + }[]; + volunteers: { + _id: string; + user: { + _id: string; + }; + }[]; +} + +export interface InterfaceVolunteerMembership { + _id: string; + status: string; + createdAt: string; + event: { + _id: string; + title: string; + startDate: string; + }; + volunteer: { + _id: string; + user: InterfaceUserInfo; + }; + group: { + _id: string; + name: string; + }; +} + +export interface InterfaceVolunteerRank { + rank: number; + hoursVolunteered: number; + user: { + _id: string; + firstName: string; + lastName: string; + email: string; + image: string | null; + }; +} diff --git a/src/utils/organizationTagsUtils.ts b/src/utils/organizationTagsUtils.ts index 5f81497c65..56654a3abb 100644 --- a/src/utils/organizationTagsUtils.ts +++ b/src/utils/organizationTagsUtils.ts @@ -1,5 +1,13 @@ // This file will contain the utililities for organization tags +import type { ApolloError } from '@apollo/client'; +import type { + InterfaceQueryOrganizationUserTags, + InterfaceQueryUserTagChildTags, + InterfaceQueryUserTagsAssignedMembers, + InterfaceQueryUserTagsMembersToAssignTo, +} from './interfaces'; + // 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': { @@ -20,4 +28,90 @@ export const dataGridStyle = { '& .MuiDataGrid-main': { borderRadius: '0.1rem', }, + '& .MuiDataGrid-topContainer': { + position: 'fixed', + top: 290, + zIndex: 1, + }, + '& .MuiDataGrid-virtualScrollerContent': { + marginTop: 6.5, + }, }; + +// the data chunk size for tag related queries +export const TAGS_QUERY_DATA_CHUNK_SIZE = 10; + +// the tag action type +export type TagActionType = 'assignToTags' | 'removeFromTags'; + +// the sortedByType +export type SortedByType = 'ASCENDING' | 'DESCENDING'; + +// Interfaces for tag queries: +// 1. Base interface for Apollo query results +interface InterfaceBaseQueryResult { + loading: boolean; + error?: ApolloError; + refetch?: () => void; +} + +// 2. Generic pagination options +interface InterfacePaginationVariables { + after?: string | null; + first?: number | null; +} + +// 3. Generic fetch more options +interface InterfaceBaseFetchMoreOptions { + variables: InterfacePaginationVariables; + updateQuery?: (prev: T, options: { fetchMoreResult: T }) => T; +} + +// 4. Query interfaces +export interface InterfaceOrganizationTagsQuery + extends InterfaceBaseQueryResult { + data?: { + organizations: InterfaceQueryOrganizationUserTags[]; + }; + fetchMore: ( + options: InterfaceBaseFetchMoreOptions<{ + organizations: InterfaceQueryOrganizationUserTags[]; + }>, + ) => void; +} + +export interface InterfaceOrganizationSubTagsQuery + extends InterfaceBaseQueryResult { + data?: { + getChildTags: InterfaceQueryUserTagChildTags; + }; + fetchMore: ( + options: InterfaceBaseFetchMoreOptions<{ + getChildTags: InterfaceQueryUserTagChildTags; + }>, + ) => void; +} + +export interface InterfaceTagAssignedMembersQuery + extends InterfaceBaseQueryResult { + data?: { + getAssignedUsers: InterfaceQueryUserTagsAssignedMembers; + }; + fetchMore: ( + options: InterfaceBaseFetchMoreOptions<{ + getAssignedUsers: InterfaceQueryUserTagsAssignedMembers; + }>, + ) => void; +} + +export interface InterfaceTagUsersToAssignToQuery + extends InterfaceBaseQueryResult { + data?: { + getUsersToAssignTo: InterfaceQueryUserTagsMembersToAssignTo; + }; + fetchMore: ( + options: InterfaceBaseFetchMoreOptions<{ + getUsersToAssignTo: InterfaceQueryUserTagsMembersToAssignTo; + }>, + ) => void; +} diff --git a/src/utils/timezoneUtils/dateTimeMiddleware.test.ts b/src/utils/timezoneUtils/dateTimeMiddleware.spec.ts similarity index 92% rename from src/utils/timezoneUtils/dateTimeMiddleware.test.ts rename to src/utils/timezoneUtils/dateTimeMiddleware.spec.ts index b14702b546..ead19444c3 100644 --- a/src/utils/timezoneUtils/dateTimeMiddleware.test.ts +++ b/src/utils/timezoneUtils/dateTimeMiddleware.spec.ts @@ -3,6 +3,7 @@ import type { Operation, FetchResult } from '@apollo/client/core'; import { Observable } from '@apollo/client/core'; import { gql } from '@apollo/client'; import type { DocumentNode } from 'graphql'; +import { describe, it, expect, vi } from 'vitest'; const DUMMY_QUERY: DocumentNode = gql` query GetDummyData { @@ -19,12 +20,12 @@ describe('Date Time Middleware Tests', () => { query: DUMMY_QUERY, operationName: 'GetDummyData', variables: { startDate: '2023-09-01', startTime: '12:00:00' }, - getContext: jest.fn(() => ({})), - setContext: jest.fn(), + getContext: vi.fn(() => ({})), + setContext: vi.fn(), extensions: {}, }; - const forward = jest.fn( + const forward = vi.fn( (op) => new Observable((observer) => { expect(op.variables['startDate']).toBe('2023-09-01'); @@ -55,12 +56,12 @@ describe('Date Time Middleware Tests', () => { query: DUMMY_QUERY, operationName: 'GetDummyData', variables: {}, - getContext: jest.fn(() => ({})), - setContext: jest.fn(), + getContext: vi.fn(() => ({})), + setContext: vi.fn(), extensions: {}, }; - const forward = jest.fn( + const forward = vi.fn( () => new Observable((observer) => { observer.next(testResponse); @@ -98,12 +99,12 @@ describe('Date Time Middleware Tests', () => { query: DUMMY_QUERY, operationName: 'GetDummyData', variables: { startDate: 'not-a-date', startTime: '25:99:99' }, - getContext: jest.fn(() => ({})), - setContext: jest.fn(), + getContext: vi.fn(() => ({})), + setContext: vi.fn(), extensions: {}, }; - const forward = jest.fn( + const forward = vi.fn( (op) => new Observable((observer) => { expect(op.variables['startDate']).toBe('not-a-date'); @@ -130,12 +131,12 @@ describe('Date Time Middleware Tests', () => { query: DUMMY_QUERY, operationName: 'GetDummyData', variables: {}, - getContext: jest.fn(() => ({})), - setContext: jest.fn(), + getContext: vi.fn(() => ({})), + setContext: vi.fn(), extensions: {}, }; - const forward = jest.fn( + const forward = vi.fn( () => new Observable((observer) => { observer.next(testResponse); @@ -188,12 +189,12 @@ describe('Date Time Middleware Tests', () => { }, }, }, - getContext: jest.fn(() => ({})), - setContext: jest.fn(), + getContext: vi.fn(() => ({})), + setContext: vi.fn(), extensions: {}, }; - const forward = jest.fn( + const forward = vi.fn( (op) => new Observable((observer) => { expect(op.variables.event.startDate).toBe('2023-10-01'); diff --git a/src/utils/timezoneUtils/dateTimeMiddleware.ts b/src/utils/timezoneUtils/dateTimeMiddleware.ts index 70fc20a026..f3be59bacb 100644 --- a/src/utils/timezoneUtils/dateTimeMiddleware.ts +++ b/src/utils/timezoneUtils/dateTimeMiddleware.ts @@ -14,6 +14,13 @@ const combineDateTime = (date: string, time: string): string => { const splitDateTime = (dateTimeStr: string): { date: string; time: string } => { const dateTime = dayjs.utc(dateTimeStr); + if (!dateTime.isValid()) { + const [date, time] = dateTimeStr.split('T'); + return { + date: date, + time: time, + }; + } return { date: dateTime.format('YYYY-MM-DD'), time: dateTime.format('HH:mm:ss.SSS[Z]'), @@ -21,18 +28,17 @@ const splitDateTime = (dateTimeStr: string): { date: string; time: string } => { }; const convertUTCToLocal = (dateStr: string): string => { - if (dayjs(dateStr).isValid()) { - return dayjs.utc(dateStr).local().format('YYYY-MM-DDTHH:mm:ss.SSS'); + if (!dayjs(dateStr).isValid()) { + return dateStr; } - return dateStr; + return dayjs.utc(dateStr).local().format('YYYY-MM-DDTHH:mm:ss.SSS'); }; const convertLocalToUTC = (dateStr: string): string => { - if (dayjs(dateStr).isValid()) { - const result = dayjs(dateStr).utc().format('YYYY-MM-DDTHH:mm:ss.SSS[Z]'); - return result; + if (!dayjs(dateStr).isValid()) { + return dateStr; // Leave the invalid value unchanged } - return dateStr; + return dayjs(dateStr).utc().format('YYYY-MM-DDTHH:mm:ss.SSS[Z]'); }; const traverseAndConvertDates = ( diff --git a/src/utils/useLocalstorage.test.ts b/src/utils/useLocalstorage.spec.ts similarity index 91% rename from src/utils/useLocalstorage.test.ts rename to src/utils/useLocalstorage.spec.ts index 7483da4da2..b84cbd86cf 100644 --- a/src/utils/useLocalstorage.test.ts +++ b/src/utils/useLocalstorage.spec.ts @@ -1,3 +1,5 @@ +// SKIP_LOCALSTORAGE_CHECK + import { getStorageKey, getItem, @@ -5,6 +7,7 @@ import { removeItem, useLocalStorage, } from './useLocalstorage'; +import { describe, it, expect, beforeEach, vi } from 'vitest'; describe('Storage Helper Functions', () => { beforeEach(() => { @@ -95,7 +98,7 @@ describe('Storage Helper Functions', () => { const storageHelper = useLocalStorage(customPrefix); const key = 'testKey'; - const spyGetStorageKey = jest.spyOn(storageHelper, 'getStorageKey'); + const spyGetStorageKey = vi.spyOn(storageHelper, 'getStorageKey'); storageHelper.getStorageKey(key); expect(spyGetStorageKey).toHaveBeenCalledWith(key); @@ -106,7 +109,7 @@ describe('Storage Helper Functions', () => { const storageHelper = useLocalStorage(customPrefix); const key = 'testKey'; - const spyGetItem = jest.spyOn(storageHelper, 'getItem'); + const spyGetItem = vi.spyOn(storageHelper, 'getItem'); storageHelper.getItem(key); expect(spyGetItem).toHaveBeenCalledWith(key); @@ -118,7 +121,7 @@ describe('Storage Helper Functions', () => { const key = 'testKey'; const value = 'data'; - const spySetItem = jest.spyOn(storageHelper, 'setItem'); + const spySetItem = vi.spyOn(storageHelper, 'setItem'); storageHelper.setItem(key, value); expect(spySetItem).toHaveBeenCalledWith(key, value); @@ -129,7 +132,7 @@ describe('Storage Helper Functions', () => { const storageHelper = useLocalStorage(customPrefix); const key = 'testKey'; - const spyRemoveItem = jest.spyOn(storageHelper, 'removeItem'); + const spyRemoveItem = vi.spyOn(storageHelper, 'removeItem'); storageHelper.removeItem(key); expect(spyRemoveItem).toHaveBeenCalledWith(key); diff --git a/tsconfig.json b/tsconfig.json index 0116d88a31..7e0274edb2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -18,5 +18,6 @@ "noEmit": true, "jsx": "react-jsx" }, - "include": ["src", "src/App.tsx", "setup.ts"] + "include": ["src", "src/App.tsx", "setup.ts"], + "exclude": ["node_modules", "dist", "vitest.config.ts"] } diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000000..3d071e7534 --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,39 @@ +import { defineConfig } from 'vitest/config'; +import react from '@vitejs/plugin-react'; +import { nodePolyfills } from 'vite-plugin-node-polyfills'; +import tsconfigPaths from 'vite-tsconfig-paths'; +import svgrPlugin from 'vite-plugin-svgr'; + +export default defineConfig({ + plugins: [ + react(), + nodePolyfills({ + include: ['events'], + }), + tsconfigPaths(), + svgrPlugin(), + ], + test: { + include: ['src/**/*.spec.{js,jsx,ts,tsx}'], + globals: true, + environment: 'jsdom', + setupFiles: 'vitest.setup.ts', + coverage: { + enabled: true, + provider: 'istanbul', + reportsDirectory: './coverage/vitest', + exclude: [ + 'node_modules', + 'dist', + '**/*.{spec,test}.{js,jsx,ts,tsx}', + 'coverage/**', + '**/index.{js,ts}', + '**/*.d.ts', + 'src/test/**', + 'vitest.config.ts', + 'vitest.setup.ts', // Exclude from coverage if necessary + ], + reporter: ['text', 'html', 'text-summary', 'lcov'], + }, + }, +}); diff --git a/vitest.setup.ts b/vitest.setup.ts new file mode 100644 index 0000000000..7b0828bfa8 --- /dev/null +++ b/vitest.setup.ts @@ -0,0 +1 @@ +import '@testing-library/jest-dom';